Mik*_*ike 7 python boolean-expression conditional-statements
它是pythonic使用or,类似于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
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
    aba*_*ert 18
不,这绝对不是Pythonic.沿途做出的许多决定都是专门用来阻止这种编码.
写这个的正确方法是显而易见的方式:
if verbose:
    print(stuff)
Run Code Online (Sandbox Code Playgroud)
或者,如果计算stuff本身并不昂贵/危险/不可撤销,只需包装print一个检查标志的函数:
def printv(*args, **kwargs):
    if verbose:
        print(*args, **kwargs)
Run Code Online (Sandbox Code Playgroud)
...所以你可以这样做,这就像你将得到的那样简洁:
printv(stuff)
Run Code Online (Sandbox Code Playgroud)
或者,更好的是,使用logging模块而不是重新发明轮子.
但是,如果stuff价格昂贵,你真的想节省一条线?
好吧,你可能不需要保存一条线,这样做总是为了简洁而牺牲可读性; "可读性计数"是Python的禅宗的关键部分.但Python确实允许您将单行套件放在与条件相同的行上:
if verbose: print(stuff)
Run Code Online (Sandbox Code Playgroud)
正如PEP 8所说,"有时它没关系",但它"通常是气馁".正如Guido把它放在想法邮件列表的电子邮件中,"如果你必须保存一行,使用一行if语句而不是'聪明'.但如果你必须保存一行,我可能不想读你的代码."
如果你想要一个表达式(你不应该这样,我将在下面解释),或者你想在技术上遵循PEP 8而在公然违反精神的情况下:
print(stuff) if verbose else None
Run Code Online (Sandbox Code Playgroud)
那么,什么不是Pythonic呢?
首先,你print在表达式中使用结果,即使print没有有用的结果,也只是为了它的副作用而被调用.这是误导.
一般来说,Python每行只有一个副作用,它尽可能地向左移动,这使得浏览代码变得容易,看看有什么变化.声明和表达之间的强烈分歧(以及,例如,作业是陈述),通过具有惯用性返回None而不是self等等的副作用的方法,强化了这一点.
但即使忽略所有这些,使用and和or仅仅为了短路,而不是为了他们的结果,可能会让人感到困惑,至少在某些人看来,这很难看.这就是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
Run Code Online (Sandbox Code Playgroud)
所以,你去,在快速通过的情况下,if声明实际上大约快 20%,而不是更慢 - 它们都是如此之快,以至于它不太可能影响你的程序.如果你在一个紧凑的循环中做了十亿次并且需要挤出那个性能,那么你就会想要将其余部分从循环中解除,即使这意味着重复自己使用两个相同的克隆代码(特别是考虑到没有prints 的循环更可能适合缓存等).
如果你想知道为什么,那么,你必须在你关心的特定实现的特定版本上查看这些字节码的实现......但最有可能的是,需要做一个额外的POP_TOP而不是将一个合并到以前的操作是差异的一部分.