简体   繁体   English

python如何执行变量分配?

[英]How does python perform variable assignment?

This is not so much a "how-to" question, as a question about how python functions to store variables. 这不是一个“ how-to”问题,而是关于python如何存储变量的问题。

As far as I understand (please correct me if i am wrong), when a variable is created in (say) C, the value is stored in memory and the address of that memory is stored under the variable name. 据我了解(如果我错了,请纠正我),在(例如)C中创建变量时,该值存储在内存中,而该内存的地址存储在变量名下。 In python it creates the value in memory, and then "tags" that memory address with the variable name. 在python中,它在内存中创建值,然后用变量名“标记”该内存地址。 So that if you do this: 因此,如果您这样做:

>>> x = 3
>>> y = x
>>> id(x)
42
>>> id(y)
42

the memory addresses are the same for x and y x和y的内存地址相同

then if i do this: 然后,如果我这样做:

>>> x = 4
>>> print y
3

as it should. 正如它应该。 If i query the addresses: 如果我查询地址:

>>> id(x)
46
>>> id(y)
42

it appears that python has created new memory for the new x value and y remains the same. 看来python为新的x值创建了新的内存,而y保持不变。 but then when i do this: 但是当我这样做时:

>>> y = 4
>>> id(y)
46

it seems that python has searched through the memory looking for a value that matches the input variable, and then tagged that memory address with the name "y" - if no such value is found then it creates a new value in memory and then tags that 似乎python已经在内存中搜索了一个与输入变量匹配的值,然后用名称“ y”标记了该内存地址-如果找不到该值,那么它将在内存中创建一个新值,然后标记该值

am i right in my thinking here? 我在这里想的对吗?

the problem that occurs to me that this is all well and good for my little "x" and "y" example, but what about a program with millions of variables? 我想到的问题是,这对于我的小“ x”和“ y”示例来说都是好事,但是对于具有数百万个变量的程序来说呢? does this mean that whenever a variable value is assigned, it has to search through the whole memory, looking for a match, before assigning new memory? 这是否意味着只要分配了变量值,就必须在分配新的内存之前搜索整个内存,寻找匹配项?

Intuitively, while this approach would definitely save a lot of space, it would probably not be very time efficient, however I imagine that a lot of people, much smarter than me, have put a lot of effort and work into making python, so obviously this isnt the case. 直观地讲,虽然这种方法肯定会节省很多空间,但可能不会节省时间,但是我认为,比我聪明得多的很多人已经投入了大量的精力和精力来制作python,因此显然事实并非如此。 So my question is what am i missing in my understanding that makes this method a good approach for memory management? 因此,我的问题是我在理解上缺少什么使这种方法成为内存管理的好方法?

Is it simply a matter that searching through the list is at most time complexity O(n), and so with fast processors, this is not really an issue? 仅仅在列表中搜索最多是时间复杂度O(n)就是一个问题,因此对于快速处理器,这实际上不是问题吗? or is there something deeper? 还是有更深的东西?

First off, what you are asking is literally defined as " implementation defined ". 首先,您要问的是字面上定义为“ implementation defined ”。

My guess is that Python is actually doing that check at compile-time, optimizing the memory layout given what it knows. 我的猜测是Python实际上是在编译时进行检查的,根据已知的知识优化了内存布局。

I can almost guarantee you it does NOT search through every variable. 我几乎可以保证您不会搜索每个变量。 First, it would have to know what's mutable and what's not (hint: "what's not" is a very short list). 首先,它必须知道什么是可变的,什么不是可变的(提示:“什么不是”是很短的清单)。 If it's mutable, it can't just re-use the old one. 如果它是可变的,则不能仅重用旧的。

There's a detailed description for the CPython implementation here: 这里有CPython实现的详细说明:

http://www.laurentluce.com/posts/python-integer-objects-implementation/ http://www.laurentluce.com/posts/python-integer-objects-implementation/

The behaviour you are seeing is because python special-cases the handling of small integers, as they are quite common. 您看到的行为是因为python特殊处理小整数,因为它们很常见。 Try this, for instance, to see a different result. 例如,尝试此操作以查看不同的结果。

>>> x = 88888888888888888888888
>>> y = 88888888888888888888888
>>> id(x)
4321062304
>>> id(y)
4321062344

variable is created in (say) C, the value is stored in memory and the address of that memory is stored under the variable name 在(例如)C中创建变量,该值存储在内存中,并且该内存的地址存储在变量名下

No. In C, the variable is created, and obtains a location in memory no later than the execution of the statement which declares it (in so far as declarations are executable). 否。在C中,将创建该变量,并在不晚于声明该变量的语句的执行(就声明是可执行的)的情况下获得其在内存中的位置。 Assignment to that variable alters its memory location. 分配给该变量会更改其存储位置。

In python it creates the value in memory, and then "tags" that memory address with the variable name. 在python中,它在内存中创建值,然后用变量名“标记”该内存地址。

Right. 对。 Or, equivalently, the variable holds a pointer (of whatever sort) to the object. 或者,等效地,该变量持有指向该对象的指针(无论何种形式)。

id

id does NOT return memory addresses. id不返回内存地址。 It returns an integer which is only returned for that specific object, during the life of that object. 它返回一个整数,该整数仅在该对象的生存期内针对该特定对象返回。

seems that python has searched through the memory looking for a value that matches the input variable 似乎python已经在内存中搜索了与输入变量匹配的值

This behaviour is implementation defined, and in CPython happens only for integers 0-127. 此行为是由实现定义的,并且在CPython中仅发生在0-127之间。 It doesn't happen in the case of any other value. 其他任何值都不会发生。 You may also be able to "defeat" this interning behaviour. 您也许还可以“击败”这种内部行为。

In addition, there is no scanning. 此外,没有扫描。 Interning likely uses an array to store the interned values, because these are integers. 实习可能使用数组存储实习值,因为这些是整数。

I am wary of saying that id represents a "memory address" - it happens to be implemented in terms of memory addresses in current versions of CPython, but this is hardly guaranteed by anything (and it is different in, for example, PyPy). 我很警惕地说id代表一个“内存地址”-它恰好是在当前版本的CPython中根据内存地址实现的,但这几乎不能得到任何保证(例如,在PyPy中是不同的)。

But other than that quibble, your thinking is roughly right, although the mechanism is a little simpler and quicker than you imagine. 但是除了那个小问题之外,您的想法大体上是正确的,尽管该机制比您想象的要简单和快捷。

What CPython (but not necessarily other implementations) does instead is to preallocate and cache a certain amount of "small" ints (currently everything from -5 up to and including 256). 相反,CPython(但不一定是其他实现)要做的是预分配和缓存一定数量的“小”整数(当前从-5到256,包括256)。 Then when one of them is requested, it finds it in this cache, instead of allocating a new Python object. 然后,当请求其中之一时,它将在此缓存中找到它,而不是分配新的Python对象。 But instead of the O(n) linear search you imagine, it is actually implemented as an O(1) C array lookup. 但是,您可以想象它不是O(n)线性搜索,而是实际上实现为O(1)C数组查找。 You can see how it works in CPython's intobject.c : 您可以在CPython的intobject.c中查看其工作方式

#ifndef NSMALLPOSINTS
#define NSMALLPOSINTS           257
#endif
#ifndef NSMALLNEGINTS
#define NSMALLNEGINTS           5
#endif
#if NSMALLNEGINTS + NSMALLPOSINTS > 0
/* References to small integers are saved in this array so that they
   can be shared.
   The integers that are saved are those in the range
   -NSMALLNEGINTS (inclusive) to NSMALLPOSINTS (not inclusive).
*/
static PyIntObject *small_ints[NSMALLNEGINTS + NSMALLPOSINTS];
#endif
#ifdef COUNT_ALLOCS
Py_ssize_t quick_int_allocs;
Py_ssize_t quick_neg_int_allocs;
#endif

PyObject *
PyInt_FromLong(long ival)
{
    register PyIntObject *v;
#if NSMALLNEGINTS + NSMALLPOSINTS > 0
    if (-NSMALLNEGINTS <= ival && ival < NSMALLPOSINTS) {
        v = small_ints[ival + NSMALLNEGINTS];
        Py_INCREF(v);
#ifdef COUNT_ALLOCS
        if (ival >= 0)
            quick_int_allocs++;
        else
            quick_neg_int_allocs++;
#endif
        return (PyObject *) v;
    }
#endif
    if (free_list == NULL) {
        if ((free_list = fill_free_list()) == NULL)
            return NULL;
    }
    /* Inline PyObject_New */
    v = free_list;
    free_list = (PyIntObject *)Py_TYPE(v);
    PyObject_INIT(v, &PyInt_Type);
    v->ob_ival = ival;
    return (PyObject *) v;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM