Python和C中每行的多个属性

时间:2018-07-15 23:52:19

标签: python c translation

尽最大努力了解python的工作原理。我来自扎实的C背景。

尝试将以下行转换为C:     p, q = q, p - x // y * q

我的问题是,多个断言/属性(请在术语上对我进行纠正)无法按我期望的那样工作。

该行代码实际上如何解译为类似C的语法?

2 个答案:

答案 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中,它实际上 did 优化了元组,还优化了临时局部变量,并且仅将中间值匿名存储在堆栈中。


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撰写。