Python 不在变量中存储值,而是为对象分配名称。locals()函数将返回当前命名空间(或更具体地说,当前范围)中的所有名称。让我们开始一个新的口译会话,看看locals()
会给我们带来什么。
>>> locals()
{'__builtins__': <module '__builtin__' (built-in)>, '__name__': '__main__', '__doc__': None, '__package__': None}
当前在命名空间中的唯一名称是 Python 在启动时放置在那里的名称。这是一个快速的单行代码,仅向我们显示我们分配的名称:
>>> {k:v for k,v, in locals().iteritems() if k[0] != '_'}
{}
这样更好。不要担心单线是如何工作的,让我们继续创建一个类。
>>> class C(object):
greeting = "I'm the first class"
当我们定义一个类时,它的名称在当前范围内的位置:
>>> {k:v for k,v, in locals().iteritems() if k[0] != '_'}
{'C': <class '__main__.C'>}
这部分是 Python 的说法,即有一个对象太大而无法打印出来,但它是我们定义的类对象。让我们看看我们的类对象存储的内存地址。我们可以使用id()函数来找出答案。
>>> id(C)
18968856
返回的数字id()
是参数的内存位置。如果您自己运行这些命令,您将看到一个不同的数字,但该数字在单个会话期间不会改变。
>>> id(C)
18968856
现在让我们创建一个实例。
>>> c = C()
>>> c.greeting
"I'm the first class"
现在,当我们查看 时locals()
,我们可以看到我们的类对象和实例对象。
>>> {k:v for k,v, in locals().iteritems() if k[0] != '_'}
{'C': <class '__main__.C'>, 'c': <__main__.C object at 0x011BDED0>}
每个实例对象都有一个特殊成员__class__
,它是对实例所属的类对象的引用。
>>> c.__class__
<class '__main__.C'>
如果我们调用该变量,我们可以看到它是对我们刚刚定义id()
的类的引用:C
>>> id(c.__class__)
18968856
>>> id(c.__class__) == id(C)
True
现在让我们C
从本地命名空间中删除名称:
>>> del C
>>> {k:v for k,v, in locals().iteritems() if k[0] != '_'}
{'c': <__main__.C object at 0x011BDED0>}
>>> C
Traceback (most recent call last):
File "<pyshell#16>", line 1, in <module>
C
NameError: name 'C' is not defined
这正是我们所期望的。该名称C
不再分配给任何东西。但是,我们的实例仍然有对类对象的引用。
>>> c.__class__
<class '__main__.C'>
>>> id(c.__class__)
18968856
如您所见,该类仍然存在,只是您无法通过C
本地命名空间中的名称来引用它。
让我们创建一个名为 的第二个类C
。
>>> class C(object):
greeting = "I'm the second class"
>>> {k:v for k,v, in locals().iteritems() if k[0] != '_'}
{'C': <class '__main__.C'>, 'c': <__main__.C object at 0x011BDED0>}
如果我们创建第二个类的实例,它的行为就像您注意到的那样:
>>> c2 = C()
>>> c2.greeting
"I'm the second class"
>>> c.greeting
"I'm the first class"
要了解原因,让我们看一下id
这个新类。我们可以看到新的类对象与我们的第一个对象存储在不同的位置。
>>> id(C)
19011568
>>> id(C) == id(C.__class__)
False
这就是实例仍然可以正常工作的原因:两个类对象仍然单独存在,并且每个实例都持有对其对象的引用。