I'm currently writing a program in Python to model projective geometry, and the congruence function for a projective point is looking rather nasty.
(for anyone interested, two projective points are congruent if they both lie on a single line passing through the origin.)
class Point(object):
def __init__(self, a, b, c):
self.coords = [ a, b, c ]
def congruent(self, other):
ratio = 0
for i in range(3):
if self.coords[i] != 0 and other.coords[i] != 0:
if ratio is 0:
ratio = other.coords[i] / self.coords[i]
elif ratio != other.coords[i] / self.coords[i]:
return False
elif self.coords[i] != 0 or other.coords[i] != 0:
return False
return True
I'm new to Python, but I know that there's generally a "Pythonic" way to do everything. With that in mind, how would I go about making this more readable?
答案 0 :(得分:3)
How about this:
def congruent(self, other, eps=0.001):
ratios = (c1 / c2 for c1, c2 in zip(self.coords, other.coords) if c1 or c2)
try:
first = next(ratios)
return all(abs(ratio - first) < eps for ratio in ratios)
except ZeroDivisionError:
return False
zip
is handy).c1
is nonzero and c2
is zero, so that's a fail.Note: If you're not using Python 3, you should add from __future__ import division
to the top of your file so that you don't get incorrect results for integer coordinate values.
Edit: added short-circuiting and epsilon-comparison for float ratios per @JoranBeasley.
答案 1 :(得分:1)
Maybe use if self.coords[i]
instead of if self.coords[i] != 0
(same for similar examples) and if not ratio
instead of if ratio is 0
. In Python, any nonzero value passes if
clause, so you don't need to check if it is nonzero, it is automatic.
答案 2 :(得分:1)
def congurent(self,other):
ratio = None
for a,b in zip(self,other):
if a != 0 and b != 0:
if ratio is None:
ratio = a/float(b)
elif abs(ratio - a/float(b))>0.001:
return False
elif a!=0 or b!=0:
return False
return True
is perhaps a little more pythonic... although all its really changing is how you iterate over the list (its the same number of lines)