python - 使用 `or` 会不会是 Pythonic,类似于 PHP 使用 `or die()` 的方式?

标签 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

对比 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很贵,你真的要省线吗?

好吧,您可能真的不需要保存一行,这样做总是为了简洁而牺牲可读性; “可读性计数”是 the Zen of 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明确表示您正在创造一个值(value),然后您什么都不做;显式总是比隐式好,尤其是当你做一些不常见的事情时。

最后,至于性能:(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%,而不是更慢——而且它们都非常快,无论如何都不太可能影响您的程序。如果你在一个紧凑的循环中这样做了 10 亿次并且需要挤出那个性能,你会想要将其余的从循环中提升出来,即使这意味着用两个相同的近似克隆来重复自己代码(特别是考虑到没有 print 的循环更有可能适合缓存等)。

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

关于python - 使用 `or` 会不会是 Pythonic,类似于 PHP 使用 `or die()` 的方式?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26664855/

相关文章:

Python 在两次使用一个值时避免使用变量?

python - 在python中将图像转换为字节文字

Jenkins:如何根据复选框参数条件跳过 Jenkins 管道中的一个阶段?

sql - sqlite3 : error?中的OR语句

java - <s :if> test expression evaluation for boolean value doesn't work as expected

python - 如何使用类中的方法来比较该类的两个对象

Python修改全局变量

c++ - Switch 语句而不是多个嵌套的 if - else?

python - python中的条件矩阵运算

python - Python 中 NOT、AND、OR 的逻辑运算符的优先级(运算顺序)