在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}
为什么会这样?
ETA:
y[x[0]] = x[0] = y.get(x[0], len(y))
产生预期的行为(这让我很懊恼。)
答案 0 :(得分:5)
Ruby和Python是不同的语言,并做出不同的选择。在Python中,分配是语句,并从从左到右评估多个分配目标。 Ruby做出了其他选择;作业是表达式,因此以相反的顺序进行评估。
所以在Ruby中会发生这种情况:
y.fetch(x[0], y.length)
,生成0
(密钥丢失,y
为空)。y[x[0]] = 0
,y['a'] = 0
。这是一个导致0
。x[0] = 0
(0
作为y[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]
,这只是非常混乱。