0

我到处听说变量是 Python 中的“名称,而不是存储”,重要的是不要将它们视为存储,但我还没有找到一个例子来说明为什么这很重要。所以问题是,为什么区分变量是名称和变量是存储很重要?

4

3 回答 3

6
a = SomeObject()
b = a

如果名称是存储(例如在 C 和 C++ 中),那么两者ab都将包含一个对象:

a +---------+
  | value 1 |
  +---------+

b +---------+
  | value 2 |
  +---------+

因此,例如,a.x = ...将对值 1 进行操作,而值 2 则完全不涉及。请注意,这样做的语言提供的值允许通过另一个值操作一个值(例如指针)。但是,这与本主题无关,您可以在 Python 的模型中做类似的事情。

在 Python 和类似语言中,内存看起来更像这样:

a +-------------+
  | reference 1 | ---------+
  +-------------+          v
                      +---------+
                      | value 1 |
                      +---------+
b +-------------+          ^
  | reference 2 | ---------+
  +-------------+

这里的引用是一个虚构的标记,它指的是(duh!)对象。任何对象都可以有任意数量的引用,对象不知道其中任何一个,如果没有对它的引用,对象仍然可以徘徊。还要注意,变量并不是唯一可以弹出引用的地方——列表包含引用,字典包含引用,对象的属性包含引用等。它有点像 C 中的指针,只是它不是可识别的值,更不用说对象了,在语言中(因此也不存在与指针算术等价的东西)。

最明显的后果是变量可以别名,因此value #1通过一个的突变可以通过另一个看到:

a.something = 1
b.something = 2
assert a.something == 2

变量的重新分配不是值 1 的突变,它只是改变了引用。也就是说,a = ...不影响b,反之亦然!

于 2013-04-27T08:56:51.050 回答
1

不像 C 语言,变量“包含”数据。
在 Python 中,名称是对数据存储位置的引用。

所以,使用列表(可变)

>>> x = [10]
>>> y = x
>>> id(x) == id(y) # they refer to the same object
True
>>> y.append(1) # manipulate y
>>> x # x is manipulated
[10, 1]
>>> y # and so is y.
[10, 1]

并带有字符串(不可变)

>>> x = '10'
>>> y = x
>>> id(x) == id(y)
True
>>> y += '1' # manipulate y
>>> id(x) == id(y) # the ids are no longer equal
False
>>> x # x != y
'10'
>>> y
'101'

当你del是一个变量时,你删除了对对象的引用,当一个对象有 0 个引用时,它被垃圾收集。

于 2013-04-27T08:49:34.377 回答
0

这种东西通常用画框和箭头来解释:

C:

pos = { .x = 1, .y = 2 }

-------            -----------
| pos |----------->| x:1 y:2 |
-------            -----------

pos2 = pos 

-------            -----------
| pos |----------->| x:1 y:2 |
-------            -----------

-------            -----------
| pos2|----------->| x:1 y:2 |
-------            -----------

pos2.x = 9

-------            -----------
| pos |----------->| x:1 y:2 |
-------            -----------

-------            -----------
| pos2|----------->| x:9 y:2 |
-------            -----------

Python:

pos = { 'x':1, 'y': 2 }

-------            -----------        -----------
| pos |----------->| 0xabcde |------->| x:1 y:2 |
-------            -----------        -----------

pos2 = pos                       

-------            -----------  
| pos |----------->| 0xabcde |--\
-------            -----------  |     -----------
                                |---->| x:1 y:2 |
-------            -----------  |     -----------
| pos2|----------->| 0xabcde |--/ 
-------            -----------  

pos2.x = 9                       

-------            -----------  
| pos |----------->| 0xabcde |--\
-------            -----------  |     -----------
                                |---->| x:9 y:2 |
-------            -----------  |     -----------
| pos2|----------->| 0xabcde |--/ 
-------            -----------  

也就是说,python 变量本质上是指针。它们不包含“值”,而是值的地址。当您将一个变量分配给另一个变量时,您只是在复制地址。当你改变一个变量时,你实际上是在改变它的基础值。

@delnan 的画更好(?),但他们错过了一个重要的点:

python中的变量不是抽象的“名称”。它们确实有值,这些值不是神秘的“引用”,它们是非常具体的内存地址。对变量的每次访问都涉及双重间接:首先我们获得一个变量的值(这是一个地址),其次,我们查看谁“生活”在这个地址上。

请注意,python 在这方面并不是唯一的,其他“脚本”语言使用类似的机制。

于 2013-04-27T09:02:40.640 回答