使用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
,等等,都强化了这一点。
但是,即使忽略所有这些,仅仅使用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
所以你去,在快速传递的情况下,if
语句实际上快了大约 20%,而不是更慢——而且它们都非常快,以至于无论如何都不太可能影响你的程序。如果你在一个紧密循环中这样做十亿次并且需要挤出该性能,你会想要将其余部分从循环中移除,即使这意味着用两个近乎克隆的相同代码重复自己(特别是考虑到没有print
的循环更有可能适合缓存, 等(。
如果你想知道为什么,那么,你必须看看这些字节码在你关心的特定实现的特定版本上的实现......但最有可能的是,需要执行额外的POP_TOP
而不是将一个合并到以前的操作中是差异的一部分。
我不认为这是pythonic。("显式优于隐式"(。
你可以写
if verbose: print(stuff)
因此,如果您迫切需要保持线路倒计时,您可以。
最python化的方式("可读性很重要"(仍然是使用
if verbose:
print(stuff)