嵌套条件语句中的可读性

3
我正在使用Python编写一个用于模拟射影几何的程序,其中射影点的同余函数看起来相当复杂。(对于任何感兴趣的人,如果两个射影点都位于通过原点的单条直线上,则它们是同余的。)
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

我是Python的新手,但我知道通常有一种“Pythonic”的方法可以完成所有事情。 有了这个想法,我应该怎么做才能让代码更易读呢?


1
这个问题似乎是主观的,基于讨论和观点... 没有一个客观的答案。 - Yeo
1
在代码检查比率为0后,它将比率分配给一个新值。之后,比率就不应该被重新分配了。 不过,可能还有更好的方法来做这件事。 - Patrick
1
@Patrick,在循环外使用0坐标设置比率,然后从索引1开始循环。这将使它更清晰,表明在循环期间不应该改变。 - Paul Butcher
1
我投票关闭此问题,因为它应该迁移到http://codereview.stackexchange.com/。 - Robert H
5
关闭问题对于迁移没有任何帮助,如果您认为应该迁移,请点击“标记”->需要管理员干预->说明您认为应该迁移。 - Simon Forsberg
显示剩余10条评论
3个回答

3
这个怎么样:
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. 如果可能的话,优先直接操作元素而不是索引(zip 很方便)。
  2. 列表推导式获取所有坐标比例,其中任一坐标为非零值。如果两个坐标都是非零的,则没问题,它将被排除在外。
  3. 只有当 c1 不为零且 c2 为零时才会发生 ZDE,因此这是一个失败的情况。
  4. 最后,如果所有比例相等,则通过。

注意:如果您没有使用 Python 3,则应在文件顶部添加 from __future__ import division,以便对于整数坐标值不会得到错误的结果。

编辑:根据 @JoranBeasley 的建议添加了短路和浮点比率的 epsilon 比较。


Bah比我的好多了。我觉得你可以使用all和generator来进行一些短路操作,但是非常好的答案,加一。 - Joran Beasley
@JoranBeasley 是的,我考虑过把 all 放到 try 里面,这只需要进行一个简单的替换,但是会影响可读性。 - tzaman
"0.0/0.0" 给了我一个 ZDE,所以不完全确定那部分是否能按预期工作,但看起来足够可信。 - Joran Beasley
2
@JoranBeasley 添加了短路,看看吧 :). 如果两个都是 0.0,那么它们将从比率列表中被排除,因为 if c1 or c2False - tzaman
Point(1,1,1).congruent(Point(0,0,0)) 返回 False。 - Stefan Pochmann

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

它可能更符合Python风格...尽管它真正改变的只是你如何迭代列表(行数相同)


太好了。abs(ratio - a/float(b))>0.001 是用于浮点数比较的吗? - Patrick
由于浮点数的计算方式,要测试浮点数的相等性确实有些困难。 :P - Joran Beasley

1
也许可以使用 if self.coords[i] 替代 if self.coords[i] != 0(类似的例子也是如此),并且使用 if not ratio 替代 if ratio is 0。在Python中,任何非零值都会通过 if 语句,因此您无需检查它是否为非零值,这是自动的。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接