带有列表索引分配、dict 索引分配和 dict.get 的 Python 分配怪癖 [英] Python assignment quirk w/ list index assign, dict index assign, and dict.get

查看:32
本文介绍了带有列表索引分配、dict 索引分配和 dict.get 的 Python 分配怪癖的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在 ruby​​ 2.4 中:

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

在 Python 3.5 中:

x = ['a']y = {}x[0] = y[x[0]] = y.get(x[0], len(y))打印(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(key 丢失,y 为空).
  • y[x[0]] = 0,所以y['a'] = 0.这是一个结果为 0 的表达式.
  • 求值 x[0] = 0(0y[x[0]] = 0 赋值表达式的结果).

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

在 Python 中会发生这种情况:

  • 求值 y.get(x[0], len(y)),产生 0(key 丢失,y 为空).
  • 计算 x[0] = 0.
  • y[x[0]] = 0,所以y[0] = 0.

来自 Python 赋值语句文档:><块引用>

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

所以右边的表达式求值,然后从左到右分配给每个目标.

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

如果 a = 42:

如果 a == 42:

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

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

In ruby 2.4:

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

In python 3.5:

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

Why this?

ETA:

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

produces expected behavior (much to my chagrin.)

解决方案

Ruby and Python are different languages, and make different choices. In Python assignments are statements and evaluates multiple assignment targets from left to right. Ruby made other choices; assignments are expressions and as a result are evaluated in the opposite order.

So in Ruby this happens:

  • Evaluate y.fetch(x[0], y.length), produces 0 (key is missing, y is empty).
  • Evaluate y[x[0]] = 0, so y['a'] = 0. This is an expression resulting in 0.
  • Evaluate x[0] = 0 (0 being the result of the y[x[0]] = 0 assignment expression).

Note that in Ruby, an assignment is an expression. It can be nested inside other expressions, and the result of the assignment expression is the value of the target after assignment.

In Python this happens instead:

  • Evaluate y.get(x[0], len(y)), produces 0 (key is missing, y is empty).
  • Evaluate x[0] = 0.
  • Evaluate y[x[0]] = 0, so y[0] = 0.

From the 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.

So the expression on the right-hand-side is evaluated first, and then assignment takes place to each target from left to right.

Python made assignments statements on purpose, because the difference between:

if a = 42:

and

if a == 42:

is so damn hard to spot, and even if intentional really hurt the readability of code. In Python, readability counts. A lot.

Generally speaking, you really want to avoid making assignments to names that are then also used in subsequent assignments in the same statement. Don't assign to x[0] and then use x[0] again in the same assignment, that's just hugely confusing.

这篇关于带有列表索引分配、dict 索引分配和 dict.get 的 Python 分配怪癖的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆