使用哪个三元运算符?

时间:2014-01-16 19:34:10

标签: python python-2.7 syntax python-2.x

我一直在想我是否应该写

lambda pixel: (0,0,0) if pixel == (0,0,0) else (255,255,255),

lambda pixel: pixel if pixel == (0,0,0) else (255,255,255),

这可能是一个愚蠢的问题,但我想更好地形成问题。

我想知道是否有任何我不知道的警告。

我个人认为后者更具可读性。

2 个答案:

答案 0 :(得分:7)

绝对是后者。

如果您使用前者,并且有人只编辑其中一个文字值,那么它现在已经坏了:

lambda pixel: (0,0,0) if pixel == (0,0,8) else (255,255,255),

我在上面介绍了一个错误。我编辑了条件中使用的元组,但没有编辑第一个元组。通过随意检查很难发现这一点。

考虑一下:

big_long_expression if something == big_long_expression else whatever

读者每次都必须在心理上评估big_long_expression,并比较它们是否实际相同。如果您改为使用后一种形式,现在很清楚:您要么保持表达式不变,要么在其他情况下返回其他形式。

这与我更喜欢+=运算符的原因相同:

my_class.a.b[i+3] = my_class.a.b[i+3] + 2

与之比较:

my_class.a.b[i+3] += 2

两者都做同样的事情,但第二部分更容易理解。

我总是更喜欢更清楚地表达你意图的语法。我认为你的第二种格式最清楚:检查一个条件,当它真的保留值时,否则返回一个特殊值。

编辑:直接在这个问题的评论中,@ DSM提出了一个很好的观点。第一个表达式也有一个微妙的属性:它总是返回一个元组,即使被比较的表达式不是一个元组。只要pixel是可以与元组进行比较的任何类,任何一个表达式都可以。但是如果你希望你的lambda始终从三元组的任何一个案例中返回一个元组,那么第一个形式更可取。

以下是您的代码的两次重写,供您考虑。

第一个:

ORIGIN = (0, 0, 0)
lambda pixel: ORIGIN if pixel == ORIGIN else (255,255,255),

现在至少有一个点可以编辑来改变原点。如果你想要总是返回一个元组,这就是我推荐的方式。

第二个:

lambda pixel: pixel if pixel == (0, 0, 0) else type(pixel)((255, 255, 255))

这将获得pixel的类型,然后调用该类型来构造新对象。这假设pixel是一个不仅与元组相当的类,而且如果你将一个元组传递给它,它将使用它来基于元组构建一个新的类实例。 / p>

使用中的一个例子:

f = lambda pixel: pixel if pixel == (0, 0, 0) else type(pixel)((255, 255, 255))

class T(tuple):
    """
    Make a class that acts exactly like a tuple.
    """
    pass

x = T((1,2,3))
assert type(x) == T
assert type(x) == type(f(x))

x = (1, 2, 3)
assert type(x) == tuple
assert type(x) == type(f(x))

答案 1 :(得分:3)

嗯,这肯定不是语法问题;这只是一种风格问题。 (在一个更复杂的表达中,它将是一个不同的故事......但是在一个更复杂的表达中,通常你应该把它分解成更简单的表达式......)

就个人而言,我认为它们都非常易读。第一个强调(0, 0, 0)是更清楚的默认值,而第二个强调更清楚地回归的目的,并且它重复一个更简单的事情(pixel而不是{{1 }})。但这些都是如此微不足道的好处,我认为这并不重要。