尽最大努力了解python的工作原理。我来自扎实的C背景。
尝试将以下行转换为C:
p, q = q, p - x // y * q
我的问题是,多个断言/属性(请在术语上对我进行纠正)无法按我期望的那样工作。
该行代码实际上如何解译为类似C的语法?
答案 0 :(得分:4)
任何assignment statement的工作方式都是首先评估右侧的表达式,然后将其分配给目标列表。 1
在您的情况下,右侧是带有两个元素的tuple display:
q, p - x // y * q
因此,Python计算第一个元素q
,然后计算第二个元素p - x // y * q
,然后根据这两个值构建一个元组。
接下来,由于您的目标列表左侧有两个目标,因此Python使用可迭代的拆包(在同一元组和序列教程部分中进行了介绍) 2 将该元组拆包为两个单独的值,然后为每个目标分配一个。
所以,用C语言来说,大致是:
_tmp1 = q
_tmp2 = p - x // y * q
_tmp3 = (_tmp1, _tmp2)
p = _tmp3[0]
q = _tmp3[1]
实际上,一个真正的Python实现可能会优化build-a-tuple / unpack-a-tuple代码,就像您自己编写此代码一样,因此获得的结果更像是:
_tmp = p - x // y * q
p = q
q = _tmp
如果您习惯使用C,则可能习惯于查看编译器生成的程序集(未禁用优化)以了解真正的含义。您可以使用dis
模块在Python中执行相同的操作,不同之处在于汇编语言是针对CPython字节码而不是x86_64或ARM9或其他任何语言:
>>> import dis
>>> dis.dis('p, q = q, p - x // y * q')
1 0 LOAD_NAME 0 (q)
2 LOAD_NAME 1 (p)
4 LOAD_NAME 2 (x)
6 LOAD_NAME 3 (y)
8 BINARY_FLOOR_DIVIDE
10 LOAD_NAME 0 (q)
12 BINARY_MULTIPLY
14 BINARY_SUBTRACT
16 ROT_TWO
18 STORE_NAME 1 (p)
20 STORE_NAME 0 (q)
22 LOAD_CONST 0 (None)
24 RETURN_VALUE
并且您可以看到,在CPython 3.7中,它实际上
1。稍微简化了一下,因为像spam[eggs][0] = …
这样的目标实际上需要将spam[eggs]
当作表达式,然后将<the result of that>[0]
当作目标…………但这在此无关紧要。
2。本教程将其称为“序列解压缩”,因为它还没有达到“可迭代”的概念。
答案 1 :(得分:2)
您可以使用以下方法在C中做等效的事情:
temp = p - x / y * q;
p = q;
q = temp;
但是真正发生的是,右侧创建了一个元组,元组项从左到右构建:
t = (q, p - x // y * q)
然后该元组在左侧解开:
p = t[0]
q = t[1]
使用元组进行基本并行分配非常方便。而且我相信您会很快适应它的。
但是,可能需要花费一点时间才能适应的一件事是Python的数据模型,它的工作方式与C的完全不同。您可能会发现这篇文章很有帮助:Facts and myths about Python names and values,由资深退伍军人Ned Batchelder撰写。