Readability in nested conditional statements

时间:2015-05-04 19:33:35

标签: python conditional-statements code-readability

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?

3 个答案:

答案 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
  1. Prefer operating directly over elements instead of on indices if possible (zip is handy).
  2. The list comprehension gets all coord ratios for cases where either coordinate is non-zero. If both are, it's fine, and it gets excluded.
  3. The ZDE only happens if c1 is nonzero and c2 is zero, so that's a fail.
  4. At the end, we pass if all ratios are equal.

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)