使用`或'是pythonic,类似于PHP如何使用`或die()`?

时间:2014-10-30 23:00:18

标签: python conditional-statements boolean-expression

使用or是pythonic,类似于PHP使用or die()的方式吗?

我一直在使用
quiet or print(stuff)
而不是 if verbose: print(stuff)
最近。

我认为它看起来更好,它们做同样的事情,并且它节省了一条线。在表现方面,一个人会比另一个好吗?

两者的字节码看起来几乎和我一样,但我真的不知道我在看什么...

or

  
  2           0 LOAD_FAST                0 (quiet)
              3 JUMP_IF_TRUE_OR_POP     15
              6 LOAD_GLOBAL              0 (print)
              9 LOAD_CONST               1 ('foo')
             12 CALL_FUNCTION            1 (1 positional, 0 keyword pair)
        >>   15 POP_TOP
             16 LOAD_CONST               0 (None)
             19 RETURN_VALUE

vs if


  2           0 LOAD_FAST                0 (verbose)
              3 POP_JUMP_IF_FALSE       19

  3           6 LOAD_GLOBAL              0 (print)
              9 LOAD_CONST               1 ('bar')
             12 CALL_FUNCTION            1 (1 positional, 0 keyword pair)
             15 POP_TOP
             16 JUMP_FORWARD             0 (to 19)
        >>   19 LOAD_CONST               0 (None)
             22 RETURN_VALUE

2 个答案:

答案 0 :(得分:18)

不,这绝对不是Pythonic。沿途的许多决定都是专门阻止这种编码的。


写这个的正确方法显而易见:

if verbose:
    print(stuff)

或者,如果计算stuff本身并不昂贵/危险/不可撤销,只需将print包装在检查标志的函数中:

def printv(*args, **kwargs):
    if verbose:
        print(*args, **kwargs)

...所以你可以这样做,这就像你将得到的那样简洁:

printv(stuff)

或者,更好的是,使用logging模块而不是重新发明轮子。


但是如果stuff价格昂贵,而你真的想保存一条线呢?

嗯,你可能真的不需要保存一条线,这样做总是为了简洁而牺牲可读性; “可读性计数”是the Zen of Python的关键部分。但Python允许您将单行套件放在与条件相同的行上:

if verbose: print(stuff)

正如PEP 8所说,“有时它没关系”,但它“通常气馁”。正如Guido把它放在想法邮件列表的电子邮件中,“如果你必须保存一行,使用一行if语句而不是'聪明'。但如果你必须保存一行,我可能不想读你的代码。“

如果你想要一个表达式(你不应该这样,我将在下面解释),或者你想技术上按照PEP 8来信,同时公然违反精神:< / p>

print(stuff) if verbose else None

那么,什么不是Pythonic呢?

首先,你在表达式中使用print的结果,即使print没有有用的结果,并且仅为其副作用调用。这是误导性的。

一般来说,Python每行只有一个副作用,它尽可能地向左移动,这使得浏览代码变得容易,看看有什么变化。声明和表达之间的强烈分歧(以及,例如,作业是陈述),通过惯用法返回None而不是self等副作用的方法强化了这一点,等等。

但即使忽略了所有这些,使用andor仅仅为了短路,而不是为了他们的结果,可能会让人感到困惑,至少在某些人看来,这很难看。这就是添加三元表达式(spam if eggs else beans)的原因:阻止人们写eggs and spam or beans。为什么会让人困惑?首先,它根本不像英语那样读取,除非你一直在阅读比实际英语更多的Perl代码。另一方面,很容易意外地使用恰好是假的有效值;你知道不要这样做,当你看到if但是你不在这里时要检查一下。另请注意,print(stuff) if verbose else None明确表示您正在创建一个随后不执行任何操作的值;显然总是比隐含更好,但尤其如此,当你做一些不常见的事情时。


最后,至于性能:(a)谁在乎,以及(b)为什么不测量它而不是通过读取你不理解的字节码来猜测?

In [511]: quiet = True
In [512]: %timeit quiet or None
10000000 loops, best of 3: 48.2 ns per loop
In [513]: verbose=False
In [514]: %timeit if verbose: pass
10000000 loops, best of 3: 38.5 ns per loop

所以,在快速通过的情况下,if语句实际上约为20%更快,而不是更慢 - 而且它们都是如此之快以至于不太可能无论如何都会影响你的程序。如果你在一个紧凑的循环中做了十亿次并且需要挤出那个性能,那么你就会想要将其余部分从循环中解除,即使这意味着重复自己使用两个相同的克隆代码(特别是考虑到没有print的循环更可能适合缓存等)。

如果你想知道为什么,那么你必须在你关心的特定实现的特定版本上查看这些字节码的实现......但最有可能的是,需要额外做{{1}而不是将一个合并到上一个操作中的是差异的一部分。

答案 1 :(得分:3)

我不认为这是pythonic。 (“明确比隐含更好”)。

可以

if verbose: print(stuff)

所以,如果你迫切需要保持你的线数,你可以。

最pythonic方式(“可读性计数。”)仍然是使用

if verbose:
    print(stuff)