【问题标题】:Using statements on either side of a python ternary conditional在 python 三元条件的任一侧使用语句
【发布时间】:2013-01-30 16:50:39
【问题描述】:

为什么禁止在 python 三元条件的两边使用语句?我看不出以下一些幼稚的语法示例可能模棱两可或损坏的任何明显原因 - 但我确信必须有充分的理由来禁止它!

>>> x, y = 0, 0
>>> (x += 1) if random.choice([0, 1]) else (y += 1)
        ^
SyntaxError: invalid syntax

>>> (x if random.choice([0, 1]) else y) += 1
SyntaxError: can't assign to conditional expression


>>> print 'hello world' if random.choice([0, 1]) else raise StandardError()
  File "<stdin>", line 1
    print 'hello world' if random.choice([0, 1]) else raise StandardError()
                                                          ^
SyntaxError: invalid syntax

您能举一个例子,说明允许在三元组中使用语句可能是危险的或定义不明确的吗?

【问题讨论】:

  • 每一种脚本语言都必须有一个专门用来迷惑 C 程序员的特性。 Lua:数组是从 1 开始的。红宝石:0 是真的。 Python:赋值是一个语句。

标签: python syntax ternary


【解决方案1】:

表达式为evaluated,语句为executed。这是完全不同的东西。

Python 开发人员已决定严格区分表达式和语句。这将使您“提前失败”,而不是最终出现难以调试的错误。

在其他语言中,例如 C(++),您可以执行以下操作

if (i=15) {...}

但你也可以这样做

if (i==15) {...}

在第一个示例中,您将 15 分配给变量 i,然后 i 的这个新值由 if 评估。

更糟糕的是递增/递减运算符。有什么区别

if (i--) {...}

if (--i) {...}

?

对于第一个示例,评估 i 的值,然后递增。对于第二个例子,顺序是相反的,所以如果i之前是1,结果就不同了。

在 Python 中,由于在其他语言中收集到此类概念的经验,语法禁止此类事情。

我不太确定这是否完全回答了您的问题,但我希望我至少可以对 Python 方法提供一些见解。

【讨论】:

  • 我认为说它们严格区分语句和表达式会更准确。赋值是语句,条件(如在 if 语句等中使用)是表达式,严格分隔意味着两者不能混用。
  • 值得注意的是,在几乎所有情况下if (i=15) 都是一个无限循环。
【解决方案2】:

这与条件表达式无关1。 Python 程序由语句组成。大多数语句的大部分部分都是表达式。表达式只包含其他表达式。

y += 1 是一个语句,不允许在需要表达式的地方使用。三元条件作为一个整体是一个表达式,它的三个部分都是表达式。没有更多的理由允许(x += 1) if random.choice([0, 1]) else (y += 1) 允许以下任何怪物:

x = (y += 1)
def foo(x=(x += 1)):
    print x
print [x += 1, x *= 10]

表达式是可以评估为某些值的事物;陈述是没有价值的东西。如果您允许语句作为条件表达式的“当为真”或“当为假”操作数,那么为什么不允许在任何表达式中使用任何语句?毕竟,它会使语法复杂化到特殊情况,因此条件表达式是唯一可以包含语句的表达式。

x = y + pass
[return True, import sys]

这些都没有任何意义。 (x += 1) if random.choice([0, 1]) else (y += 1) 也没有,因为条件表达式的全部意义在于表达式。所以会更真实地出现在语句中,比如:

z = (x += 1) if random.choice([0, 1]) else (y += 1)

您可以想象规则x += 1 的“值”是x 的值(在添加 1 之前或之后),就像 C 一样。但这使语言变得更加复杂。这仍然不能解决以下问题:

z = pass if (import sys) else (while False: print 17)

pass 的值是多少? import sys的?一个while循环?

要完成这项工作,您必须将“语句”作为存在于 Python 语法中的一类事物分离为“表达式语句”和“普通语句”,或者发明一些任意规则来确定某些特定的值是什么种说法是。可能两者兼而有之。

简单的事实是,如果你想把它写成一个单一的语句:

(x += 1) if random.choice([0, 1]) else (y += 1)

那么Python已经有了表达这个想法的语法,就是这样:

if random.choice([0, 1]):
    x += 1
else:
    y += 1

无需介绍将语句作为表达式组件的语言(和可读性)的复杂性,这样您就可以通过将 if 语句编写为条件表达式(其值被忽略)来混淆它们。


1 如果必须,可以将其称为“三元条件”,但“三元”或“三元运算符”简直是愚蠢的。它有 3 个操作数并不是最重要的。这就像调用+“二元运算符”。

【讨论】:

  • 一个很好的解释。我发现一段代码看起来像 z = (x + 1) if test() else (x += 1)
  • documentation for conditional expressions 也使用术语“三元运算符”(幸运的是不定冠词)。我同意这个词没有任何意义,真的。
【解决方案3】:

第一种语法

您的第一个语法实际上是传统的ifstatement,您尝试将其写在一行中,条件和第一个操作相反。以这种方式使用单行结构是矫枉过正的,而且丑陋且不可读。 Python 不是 C。

第二种语法

您的第二个语法不起作用,因为 Python 的条件表达式结果是 rvalue,而不是 lvalue(该链接讨论了 C 和 Microsoft,但它只是一个通用术语,出现在每种语言中)。 rvalue 是一个表达式,它可能只出现在赋值的右侧。但是,lvalue 可能出现在右侧或左侧。当lvalue 在右侧时,它的 value 仅用于评估左侧的任何内容。当lvalue在左边时,它的地址用来存放右边表达式求值后的值。

在 Python 中,一切都是引用,lvalue 允许更改引用指向的内容,但 rvalue 不允许。

例子:

a = 5 # here a is lvalue
b = a + 1 # here a is rvalue and b is lvalue

rvalue-only 表达式的另一个示例是常量。从解释器的角度来看,您的第二次尝试看起来就像

42 = 42 + 1 # WHAT THE HECK!?

为什么

至于为什么决定让条件表达式没有语句(哎呀,看起来我们已经找到原因了!):正如PEP 308所说,最初引入了条件表达式用于代替容易出错的 x and y or z 布尔表达式,由于 short-circuit 评估,它的工作原理相同。

如果 Python 要在条件句中允许 statements 和你的一样,那么它必须允许,例如 raise。在单行代码中填充大量逻辑被认为是一种糟糕的 Python 代码风格(正如我在上面所说的那样)。

看看这个

result = some_long_name / some_other_name if some_other_name != 0 else raise ZeroDivisionError

一开始它看起来像一个表达式,但它的行为就像一个语句,甚至引发异常! :( 记住 Python 建议在 79 个字符处删除行,你甚至不会在多窗口并排视图中看到 raise


【讨论】:

    【解决方案4】:

    你用的是什么版本的python? 至少在 python 2.4 中不支持此语法。以下在 python 3.3 上对我有用。在旁注中,删除括号:

    import random
    x,y=0,0
    x += 1 if random.choice([0,1]) else (y +1)
    

    【讨论】:

    • 无论random.choice() 的结果如何,你都会增加x,而不是y。您可以将x 增加1 或增加y 和1 的总和。y 保持不变。
    • 哦,这很有趣,它在 python 3 中有效,但在 python 2.7 中无效。
    • ok,其实解析为x += (1 if random.choice([0,1]) else (y +1))
    猜你喜欢
    • 2014-11-06
    • 1970-01-01
    • 2016-07-17
    • 2018-09-27
    • 2019-12-23
    • 2019-06-06
    • 2015-04-22
    • 1970-01-01
    • 2018-09-18
    相关资源
    最近更新 更多