使用“or”会不会是pythonic,类似于PHP使用“or die()”的方式



使用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

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

不,这绝对不是 Pythonic。在此过程中做出的许多决定都是为了阻止这种编码。


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

if verbose:
    print(stuff)

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

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

。所以你可以这样做,这和你将要得到的一样简洁:

printv(stuff)

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


但是,如果stuff很贵,而您真的想节省一条线怎么办?

好吧,您可能真的不需要保存一行,这样做总是为了简洁而牺牲可读性;"可读性很重要"是Python禅的关键部分。但是 Python 确实允许你将单行套件放在与条件相同的行上:

if verbose: print(stuff)

正如PEP 8所说,"有时没关系",但"通常不鼓励"。正如Guido在想法邮件列表上的一封电子邮件中所说,"如果你必须保存一行,请使用一行if语句,而不是'聪明'的东西。但是如果你必须保存一行,我可能不想阅读你的代码。

如果你想在一个表达式中做到这一点(你不应该这样做,正如我将在下面解释的那样(,或者你想在技术上遵循 PEP 8 的文字,同时公然违反精神:

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的循环更有可能适合缓存, 等(。

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

我不认为这是pythonic。("显式优于隐式"(。

你可以

if verbose: print(stuff)

因此,如果您迫切需要保持线路倒计时,您可以。

最python化的方式("可读性很重要"(仍然是使用

if verbose:
    print(stuff)

最新更新