-1

请帮助我理解为什么会这样。下面的代码列出了迭代中的重复项。但是,使用or运算符的行为类似于 if..else 语句中的 else。

j = set()
my_list = [1, 2, 3 ,3 , 3 ,4, 4]
j_add = j.add
twice = set(x for x in my_list if x in j or j_add(x))
print list(twice)

期望这条线是:

 twice = set(x for x in my_list if x in j else j_add(x))

思考或返回布尔值而不是值

4

2 回答 2

1

我可能会在这里做出一个价值判断,并说这不是好的代码,因为它使用 的短路行为or来产生副作用。

考虑给定的条件:if x in j or j_add(x).

当 时x in jor短路,跳过j_add(x)条件部分,并评估为True

当 时x not in j,检查该语句j_add(x)的真实性。此方法返回None,这是假的,因此or评估为False

因此,整个条件的评估结果与x in j. 但是有添加到j_add(x)的副作用!正在利用这种副作用以快速而肮脏的理解记录独特的成员。xjmy_list

将 更改or为 anelse仍会j根据需要进行构造,但会不恰当地将None, 的返回值添加j_add(x)twice

于 2017-08-17T15:36:09.277 回答
1

运算符返回最后评估的or参数,它可能是也可能不是布尔值。

文档中解释了此行为:

请注意,既不限制and也不or限制它们返回的值和类型FalseTrue而是返回最后评估的参数。这有时很有用,例如,如果s字符串为空,则应将其替换为默认值,则表达式会s or 'foo'产生所需的值。

当然,记住什么被解释为假和什么被解释为真的会有所帮助:

[T]以下值被解释为假:False, None, 所有类型的数字零,以及空字符串和容器(包括字符串、元组、列表、字典、集合和冻结集)。所有其他值都被解释为 true。

所以在表达式中:

A = B or C

正如@MartijnPieters 在评论中指出的那样,or表达式短路。如果第一个参数(B在这种情况下)被解释为真,则整个表达式必须为真,因此第二个参数(C)永远不会被计算。因此,第一个参数 ( B) 是“最后评估的参数”并且是返回的内容。但是,如果第一个参数 ( B) 被解释为假,则C仍必须评估第二个参数 ( ) 以确定表达式的真实性(不会发生短路)。在这种情况下,“最后计算的参数”是第二个参数 ( C),无论表达式的计算结果是真还是假,都会返回它。

有效地完成了与条件表达式相同的操作:

A = B if B else C

但是,条件表达式仅在 2.5 版中添加到 Python 中,而布尔运算符的行为从一开始就存在(或者至少存在很长时间)。大多数经验丰富的 Python 程序员很容易识别并习惯使用A = B or C. 条件表达式通常保留用于更复杂的条件,这些条件不适用于简单的条件or(例如,A = B if X else C条件不是基于Bbut的真实性X,它可以是从简单值到复杂表达式的任何内容)。

但是,您需要小心,因为正如 JaredGoguen 在他的回答中指出的那样,将 OP 示例中的 更改or为 anelse实际上会改变代码的行为。该代码的编写取决于or操作员的这种特定行为。您不能只用or条件表达式替换 for 赋值的任何使用。可能还需要额外的重构。

于 2017-08-17T15:07:33.077 回答