Python3 多重赋值和内存地址 [英] Python3 multiple assignment and memory address

查看:46
本文介绍了Python3 多重赋值和内存地址的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

阅读这篇this,与我的问题非常相似,我仍然无法理解以下行为:

a = 257乙 = 257打印(a 是 b)#Falsea, b = 257, 257打印(a 是 b)#True

在打印 id(a)id(b) 时,我可以看到在单独的行中分配值的变量具有不同的 ID,而多个赋值时,两个值都具有相同的 ID:

a = 257乙 = 257打印(id(a))#139828809414512打印(id(b))#139828809414224a, b = 257, 257打印(id(a))#139828809414416打印(id(b))#139828809414416

但是无法通过说相同值的多次赋值总是创建指向相同 id 的指针来解释这种行为,因为:

a, b = -1000, -1000打印(id(a))#139828809414448打印(id(b))#139828809414288

是否有明确的规则来解释变量何时获得相同的 id 以及何时不相同?

编辑

相关信息:本题代码以交互模式运行(ipython3)

解决方案

这是由于字节码编译器中的不断折叠优化造成的.当字节码编译器编译一批语句时,它使用一个字典 跟踪它所看到的常量.这个 dict 会自动合并任何等效的常量.

以下是负责记录和编号常量(以及一些相关职责)的例程:

静态整数compiler_add_o(struct compiler *c, PyObject *dict, PyObject *o){PyObject *t, *v;py_ssize_t arg;t = _PyCode_ConstantKey(o);如果 (t == NULL)返回-1;v = PyDict_GetItem(dict, t);如果 (!v) {arg = PyDict_Size(dict);v = PyInt_FromLong(arg);如果 (!v) {Py_DECREF(t);返回-1;}如果 (PyDict_SetItem(dict, t, v) <0) {Py_DECREF(t);Py_DECREF(v);返回-1;}Py_DECREF(v);}别的arg = PyInt_AsLong(v);Py_DECREF(t);返回参数;}

您可以看到它只会添加一个新条目并在没有找到已经存在的等效常量时分配一个新数字.(_PyCode_ConstantKey 位确保诸如 0.0-0.00 之类的东西被认为是不等价的.)>

在交互模式下,每次解释器必须实际运行您的命令时,批处理都会结束,因此常量折叠通常不会跨命令发生:

<预><代码>>>>一 = 1000>>>b = 1000>>>a 是 b错误的>>>一 = 1000;b = 1000 # 1 批次>>>a 是 b真的

在脚本中,所有顶级语句都是一个批处理,因此更多的常量折叠发生:

a = 257乙 = 257打印 a 是 b

在脚本中,这会打印 True.

函数的代码将其常量与函数外部的代码分开跟踪,这限制了常量折叠:

a = 257定义 f():乙 = 257打印 a 是 bF()

即使在脚本中,也会打印False.

After reading this and this, which are pretty similar to my question, I still cannot understand the following behaviour:

a = 257
b = 257
print(a is b) #False
a, b = 257, 257
print(a is b) #True

When printing id(a) and id(b) I can see that the variables, to which the values were assigned in separate lines, have different ids, whereas with multiple assignment both values have the same id:

a = 257
b = 257
print(id(a)) #139828809414512
print(id(b)) #139828809414224
a, b = 257, 257
print(id(a)) #139828809414416
print(id(b)) #139828809414416

But it's impossible to explain this behaviour by saying that multiple assignment of same values always creates pointers to the same id since:

a, b = -1000, -1000  
print(id(a)) #139828809414448
print(id(b)) #139828809414288

Is there a clear rule, which explains when the variables get the same id and when not?

edit

relevant info: The code in this question was run in interactive mode(ipython3)

解决方案

This is due to a constant folding optimization in the bytecode compiler. When the bytecode compiler compiles a batch of statements, it uses a dict to keep track of the constants it's seen. This dict automatically merges any equivalent constants.

Here's the routine responsible for recording and numbering constants (as well as a few related responsibilities):

static int
compiler_add_o(struct compiler *c, PyObject *dict, PyObject *o)
{
    PyObject *t, *v;
    Py_ssize_t arg;

    t = _PyCode_ConstantKey(o);
    if (t == NULL)
        return -1;

    v = PyDict_GetItem(dict, t);
    if (!v) {
        arg = PyDict_Size(dict);
        v = PyInt_FromLong(arg);
        if (!v) {
            Py_DECREF(t);
            return -1;
        }
        if (PyDict_SetItem(dict, t, v) < 0) {
            Py_DECREF(t);
            Py_DECREF(v);
            return -1;
        }
        Py_DECREF(v);
    }
    else
        arg = PyInt_AsLong(v);
    Py_DECREF(t);
    return arg;
}

You can see that it only adds a new entry and assigns a new number if it doesn't find an equivalent constant already present. (The _PyCode_ConstantKey bit makes sure things like 0.0, -0.0, and 0 are considered inequivalent.)

In interactive mode, a batch ends every time the interpreter has to actually run your command, so constant folding mostly doesn't happen across commands:

>>> a = 1000
>>> b = 1000
>>> a is b
False
>>> a = 1000; b = 1000 # 1 batch
>>> a is b
True

In a script, all top-level statements are one batch, so more constant folding happens:

a = 257
b = 257
print a is b

In a script, this prints True.

A function's code gets its constants tracked separately from code outside the function, which limits constant folding:

a = 257

def f():
    b = 257
    print a is b

f()

Even in a script, this prints False.

这篇关于Python3 多重赋值和内存地址的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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