实例字典和类字典有什么区别?

7

我正在阅读Python描述符,并看到了一行内容:

Python首先在实例字典中查找成员。如果没有找到,它会在类字典中查找。

我真的很困惑实例字典和类字典是什么

有人可以用代码解释一下吗?

我一直认为它们是相同的

6个回答

11

实例字典保存所有分配给实例的对象和值的引用,类级别字典则在类命名空间中保存所有引用。

以以下示例为例:

>>> class A(object):
...    def foo(self, bar):
...       self.zoo = bar
...
>>> i = A()
>>> i.__dict__ # instance dict is empty
{}
>>> i.foo('hello') # assign a value to an instance
>>> i.__dict__ 
{'zoo': 'hello'} # this is the instance level dict
>>> i.z = {'another':'dict'}
>>> i.__dict__
{'z': {'another': 'dict'}, 'zoo': 'hello'} # all at instance level
>>> A.__dict__.keys() # at the CLASS level, only holds items in the class's namespace
['__dict__', '__module__', 'foo', '__weakref__', '__doc__']

谢谢Burhan,那就是我想要的解释。就像我们动态分配实例字典一样,我们能否动态分配类字典呢? - user196264097
i.z = some_val ... 我想了解更多关于这个表达式。我的意思是,我认为我只能使用在 init 函数中创建的属性,但似乎不是这样。这到底是什么? - Ebram Shehata

6
我想,通过这个例子你可以理解。
class Demo(object):
    class_dict = {}   # Class dict, common for all instances

    def __init__(self, d):
        self.instance_dict = d   # Instance dict, different for each instance

同时,我们可以通过以下方式在实例中动态添加属性:

demo = Demo({1: "demo"})
demo.new_dict = {}  # A new instance dictionary defined just for this instance

demo2 = Demo({2: "demo2"})   # This instance only has one instance dictionary defined in `init` method

因此,在上面的示例中,demo实例现在有两个实例字典——一个在类外添加,另一个在__init__方法中添加到每个实例中。而demo2实例只有一个实例字典,即在__init__方法中添加的那个。
除此之外,这两个实例都有一个共同的字典——类字典。

我不明白,我们如何在类外添加属性。new_dict不是该类的数据成员。 - user196264097
1
@user9 这就是 Python 的工作方式。你可以在类的 __init__ 方法之外随时添加实例数据成员。 - Rohit Jain

2

这些字典是表示对象或类范围命名空间的内部方式。

假设我们有一个类:

class C(object):
    def f(self):
        print "Hello!"

c = C()

此时,f是在类dict中定义的方法 (f in C.__dict__),而 C.f 是 Python 2.7 中的一个未绑定方法。

c.f() 将执行以下步骤:

  • 查找 c.__dict__ 中的 f 失败
  • 查找 C.__dict__ 中的 f 成功
  • 调用 C.f(c)

现在,让我们来一个技巧:

def f_french():
    print "Bonjour!"

c.f = f_french

我们刚刚修改了对象自己的字典。这意味着c.f()现在会打印Bounjour!。这不会影响原始类行为,所以其他C的实例仍然会说英语。

你能告诉我什么是未绑定方法和绑定方法吗? - user196264097
@user9 当你编写方法时,你会发现每个方法都需要声明一个烦人的 self 参数,但在调用方法时不必传递它。当你使用 func = instance.method 时,一些神奇的事情发生了,因此 func 绑定到实例上,不需要 self(可以直接调用 func())。这就是所谓的绑定方法。另一方面,Class.method 也是可调用的,但未绑定(不知道实例),因此你必须显式地调用它,如 Class.method(instance) - bereal
在你的代码中,C.f 是一个未绑定的方法,你能给我一个例子,在类内部声明绑定的实例方法吗? - user196264097
@user196264097,你不能在类内部声明一个绑定方法,这实际上是个矛盾之语,如果我理解你的问题正确的话。 - bereal

1

类字典在该类的所有实例(对象)之间共享,而每个实例(对象)都有自己单独的实例字典副本。


0

你可以针对每个实例单独定义属性,而不是整个类。

例如:

class A(object):
    an_attr = 0

a1 = A()
a2 = A()

a1.another_attr = 1

现在a2将不再有another_attr。这是实例字典的一部分,而不是类字典。

0

Rohit Jain有最简单的Python代码来快速解释这个问题。然而,理解Java中相同的思想也是有用的,关于类和实例变量还有更多信息在这里


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接