【问题标题】:How does a tuple assignment work in low level?元组分配如何在低级别工作?
【发布时间】:2023-02-21 23:18:53
【问题描述】:

我在 Python 中尝试了以下代码片段

l1 = [0,1]
l2 = [0,1]
a, b = 0, 1
(l1[a], l1[b], l2[l1[a]], l2[l1[b]]) = (l1[b], l1[a], a, b)
print (l1)
print (l2)

结果是:

[1, 0]
[1, 0]

然而,这是我所期望的: 首先,将 a,b 插入整个表达式中

(l1[0], l1[1], l2[0], l2[1]) = (l1[1], l1[0], 0, 1)

最后它会打印:

[1, 0]
[0, 1]

在 Rust 上也一样,

fn main() {
    let mut l1 = [0,1];
    let mut l2 = [0,1];
    let (a, b) = (0, 1);
    (l1[a], l1[b], l2[l1[a]], l2[l1[b]]) = (l1[b], l1[a], a, b);
    println!("{:?}", l1);
    println!("{:?}", l2);
}

印刷

[1, 0]
[1, 0]

我对这种行为的猜测是: 只计算正确的表达式

(l1[a], l1[b], l2[l1[a]], l2[l1[b]]) = (1, 0, 0, 1)

然后分配是连续完成的:

l1[a] = 1
l1[b] = 0
l2[l1[a]] = 0 #l2[1] = 0
l2[l1[b]] = 1 #l2[0] = 1

为什么会这样?

【问题讨论】:

  • 这回答了你的问题了吗? Multiple assignment and evaluation order in Python
  • 这样想想,语法不是简单的a, b = x, y,连a, b = some_tuple都支持。如果您只写 x, y,即使没有括号,它也会创建一个元组。鉴于您正在使用的语法的常用名称“tuple unpacking”,您显然需要先有一个元组才能解包。
  • 如果你问的是 PythonRust,这是两个不同的问题。请为这个问题选择一种语言。

标签: python rust tuples


【解决方案1】:

为什么会这样?

两者都将首先全面评估 RHS,然后

对于 Python,multiple assignment (or "tuple unpacking") is a procedural affair

[...] 该对象必须是一个可迭代对象,其项目数与目标列表中的目标数相同,并且项目从左到右分配给相应的目标。

[...]

如果目标是订阅:将评估引用中的主要表达式。它应该产生一个可变序列对象(例如列表)或映射对象(例如字典)。接下来,计算下标表达式。

请注意,此评估是在每个目标的基础上完成的,因此目标为

(l1[a], l1[b], l2[l1[a]], l2[l1[b]])

该作业基本上将脱糖到:

_values = (l1[b], l1[a], a, b)
l1[a] = next(_values)
l1[b] = next(values)
l2[l1[a]] = next(values)
l2[l1[b]] = next(values)

除非您查看反汇编,否则 Python 会更高效、更积极地执行此操作,因为它使用 UNPACK_SEQUENCE 而不是一次推进可迭代的。

Rust 没有明确定义 destructuring assignment 的求值顺序,但您可以编译为 HIR 以查看它脱糖的确切内容:


fn main() {
        let mut l1 = [0, 1];
        let mut l2 = [0, 1];
        let (a, b) = (0, 1);
        {
                let (lhs, lhs, lhs, lhs) = (l1[b], l1[a], a, b);
                l1[a] = lhs;
                l1[b] = lhs;
                l2[l1[a]] = lhs;
                l2[l1[b]] = lhs;
            };

结果证明和Python差不多,为什么没有借用错误。虽然因为(再次)我找不到 assignee expression 的评估顺序的任何规范,但我不确定依赖这种行为是否安全(并不是说你也应该在 Python 中利用它,这使得阅读变得非常困难代码)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-04-17
    • 2019-04-24
    • 1970-01-01
    • 2019-09-20
    • 2012-03-06
    • 1970-01-01
    • 1970-01-01
    • 2021-01-27
    相关资源
    最近更新 更多