【问题标题】:Python assignment quirk w/ list index assign, dict index assign, and dict.get带有列表索引分配、字典索引分配和 dict.get 的 Python 分配怪癖
【发布时间】:2017-07-14 08:54:36
【问题描述】:

在 ruby​​ 2.4 中:

x = ['a']
y = {}
x[0] = y[x[0]] = y.fetch(x[0], y.length)
puts y #=> {"a"=>0}

在 python 3.5 中:

x = ['a']
y = {}
x[0] = y[x[0]] = y.get(x[0], len(y))
print(y) #=> {0: 0}

为什么会这样?

预计到达时间:

y[x[0]] = x[0] = y.get(x[0], len(y))

产生预期的行为(让我很懊恼。)

【问题讨论】:

  • 因为 Python 和 Ruby 是不同的语言? Python从左到右为一系列赋值目标赋值,Ruby从右到左。
  • @MartijnPieters 完全违反直觉的语义与编译器错误无法区分。
  • 我发现赋值表达式令人厌恶,所以我们似乎陷入了僵局。选择其他语言?
  • 请停止移动球门柱。如果您有后续问题,请发布新帖子。
  • 尽管x[0] = y[x[0]] = y.fetch(x[0], y.length) 是有效的并且在Ruby 中产生了预期的 结果,你们写这样的代码吗?这是非常令人费解的......

标签: python ruby variable-assignment


【解决方案1】:

Ruby 和 Python 是不同的语言,会做出不同的选择。在 Python 中,赋值是 语句,并从 从左到右评估多个赋值目标。 Ruby 做出了其他选择。赋值是表达式,因此以相反的顺序计算。

所以在 Ruby 中会发生这种情况:

  • 评估y.fetch(x[0], y.length),生成0(缺少键,y 为空)。
  • 评估y[x[0]] = 0,所以y['a'] = 0。这是导致0 的表达式。
  • 计算x[0] = 00y[x[0]] = 0 赋值表达式的结果)。

请注意,在 Ruby 中,赋值是一个表达式。可以嵌套在其他表达式内部,赋值表达式的结果就是赋值后目标的值。

在 Python 中会发生这种情况:

  • 评估y.get(x[0], len(y)),生成0(缺少键,y 为空)。
  • 评估x[0] = 0
  • 评估y[x[0]] = 0,所以y[0] = 0

来自 Python assignment statements documentation

赋值语句计算表达式列表(请记住,这可以是单个表达式或逗号分隔的列表,后者产生一个元组)并将单个结果对象从左到右分配给每个目标列表。

所以右侧的表达式首先被计算,然后从左到右对每个目标进行赋值。

Python 故意做出赋值语句,因为区别:

if a = 42:

if a == 42:

实在是太难发现了,即使是故意的也确实会损害代码的可读性。在 Python 中,可读性很重要。很多。

一般来说,您确实希望避免对名称进行分配,然后在同一语句中的后续分配中也使用这些名称。不要分配给x[0],然后在同一个分配中再次使用x[0],这非常令人困惑。

【讨论】:

  • 但是...这与 C 相悖?!并且无法直接将其转录为 setitem 调用!疯狂!
  • @KarlDamgaardAsmussen:为什么这么疯狂?为什么所有语言都应该在这里做出相同的选择?
  • @KarlDamgaardAsmussen:当然这可以转化为__setitem__ 电话。你只需要调整你的评估顺序。
  • @KarlDamgaardAsmussen:最重要的是:Python 中的赋值是语句,而在 C 和 Ruby 中它们是表达式。这是一个巨大的哲学差异。
  • 链式赋值显式地模拟 C。偏离 C 的行为就是违反最小意外原则。这绝对是不合情理的。让它成为一个硬错误或模仿 C。
猜你喜欢
  • 1970-01-01
  • 2014-05-04
  • 1970-01-01
  • 2021-11-23
  • 1970-01-01
  • 2020-02-03
  • 2013-05-31
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多