为什么属性引用与Python继承一样?

时间:2008-10-15 22:18:00

标签: python class inheritance

以下看起来很奇怪..基本上,somedata属性似乎在从the_base_class继承的所有类之间共享。

class the_base_class:
    somedata = {}
    somedata['was_false_in_base'] = False


class subclassthing(the_base_class):
    def __init__(self):
            print self.somedata


first = subclassthing()
{'was_false_in_base': False}
first.somedata['was_false_in_base'] = True
second = subclassthing()
{'was_false_in_base': True}
>>> del first
>>> del second
>>> third = subclassthing()
{'was_false_in_base': True}

self.somedata函数中定义__init__显然是解决这个问题的正确方法(因此每个类都有自己的somedata dict) - 但这种行为什么时候可取?

3 个答案:

答案 0 :(得分:24)

你是对的,somedata在类的所有实例和它的子类之间共享,因为它是在类 definition 时创建的。行

somedata = {}
somedata['was_false_in_base'] = False
定义类时执行

,即在创建实例时解释器遇到class语句 - 而不是时(想想Java中的静态初始化块)。如果类实例中不存在属性,则会检查类对象的属性。

在课程定义时,您可以运行arbritrary代码,如下所示:

 import sys
 class Test(object):
     if sys.platform == "linux2":
         def hello(self):
              print "Hello Linux"
     else:
         def hello(self):
              print "Hello ~Linux"

在Linux系统上,Test().hello()将打印Hello Linux,在所有其他系统上将打印另一个字符串。

相反,__init__中的对象是在 instantiation 时创建的,并且只属于实例(当它们被分配到self时):

class Test(object):
    def __init__(self):
        self.inst_var = [1, 2, 3]

在类对象而不是实例上定义的对象在许多情况下都很有用。例如,您可能希望缓存类的实例,以便可以共享具有相同成员值的实例(假设它们应该是不可变的):

class SomeClass(object):
    __instances__ = {}

    def __new__(cls, v1, v2, v3):
        try:
            return cls.__insts__[(v1, v2, v3)]
        except KeyError:
            return cls.__insts__.setdefault(
               (v1, v2, v3), 
               object.__new__(cls, v1, v2, v3))

大多数情况下,我将类主体中的数据与元类或通用工厂方法结合使用。

答案 1 :(得分:11)

请注意,您所看到的部分行为归因于somedatadict,而不是简单的数据类型,例如bool

例如,请看这个行为不同的不同示例(尽管非常相似):

class the_base_class:
    somedata = False

class subclassthing(the_base_class):
    def __init__(self):
        print self.somedata


>>> first = subclassthing()
False
>>> first.somedata = True
>>> print first.somedata
True
>>> second = subclassthing()
False
>>> print first.somedata
True
>>> del first
>>> del second
>>> third = subclassthing()
False

此示例的行为与问题中给出的行为不同的原因是因为此处first.somedata被赋予一个新值(对象True),而在第一个示例中,dict对象被引用正在修改first.somedata(以及其他子类实例)。

请参阅Torsten Marek对此答案的评论以进一步澄清。

答案 2 :(得分:2)

我认为理解这一点的最简单方法(以便您可以预测行为)是认识到您的somedata是该类的属性,而不是该类的实例(如果您以这种方式定义它)。 / p>

在任何时候实际上只有一个somedata,因为在您的示例中,您没有分配该名称,而是使用它来查找字典,然后为其分配一个项目(键,值)。这是python解释器如何工作的结果,最初会引起混淆。