Reading in nested conditional statements
I am currently writing a Python program for modeling projective geometry, and the congruence function for the projective point looks rather unpleasant.
(for anyone interested, two projective points are congruent if they both lie on the same straight line 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 there is generally a "Pythonic" way to do everything. With that in mind, how would I make it more readable?
source to share
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
- Prefers to work directly on elements rather than indexes if possible (
zip
convenient). - The comprehension of the list gets all the matching coefficients for the cases where any coordinate is nonzero. If both of them are okay and he is excluded.
- ZDE only occurs if
c1
nonzero butc2
zero, so it crashes. - At the end we will go through if all relationships are equal.
Note. If you are not using Python 3, you must add from __future__ import division
to the beginning of the file to avoid getting incorrect results for integer coordinate values.
Edit: Added short-circuiting and epsilon comparison for float coefficients for @JoranBeasley.
source to share
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
maybe a little more pythonic ... although it really does change as you iterate over the list (its the same number of lines)
source to share