Python 带有列表索引分配、字典索引分配和 dict.get 的分配怪癖

Python assignment quirk w/ list index assign, dict index assign, and dict.get

在 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))

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

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:

An assignment statement evaluates the expression list (remember that this can be a single expression or a comma-separated list, the latter yielding a tuple) and assigns the single resulting object to each of the target lists, from left to right.

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

Python故意做了赋值语句,因为两者的区别:

if a = 42:

if a == 42:

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

一般来说,您确实希望避免对随后在同一语句中的后续赋值中使用的名称进行赋值。不要赋值给 x[0],然后在同一个赋值中再次使用 x[0],那会非常混乱。