11

为什么禁止在 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

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

4

4 回答 4

7

表达式被eval引用,语句被exec引用。这是完全不同的东西。

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

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

if (i=15) {...}

但你也可以

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

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

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

if (i--) {...}

if (--i) {...}

?

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

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

我不太确定这是否完全回答了您的问题,但我希望我至少可以对 pythonic 方法有所了解。

于 2013-01-23T07:13:59.863 回答
4

这与条件表达式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 += 1x(在添加 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 个操作数并不是最重要的。这就像调用+“二元运算符”。

于 2013-01-23T07:43:58.033 回答
1

第一种语法

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

第二种语法

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

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

例子:

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

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

42 = 42 + 1 # WHAT THE HECK!?

为什么

至于为什么决定让条件表达式没有语句(哎呀,看起来我们已经找到原因了!):正如PEP 308所述,最初引入条件表达式是为了使用而不是容易出错的x and y or z布尔表达式,后者由于短路评估,工作相同。

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

看这个

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

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


于 2013-01-23T08:51:28.660 回答
-4

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

import random
x,y=0,0
x += 1 if random.choice([0,1]) else (y +1)
于 2013-01-23T07:10:26.847 回答