对象从父对象继承属性

时间:2016-05-20 13:58:29

标签: python class oop inheritance

我有一个课程定义了一个警报'然后一个定义了一个' httpalarm'。现在,httpalarm与警报共享许多相同的属性(实际上它们具有相同的属性,以及其他属性)。

我认为我应该能够做的是将这些属性定义为警报对象的一部分,然后当httpalarm创建为警报子节点时,它应该已经获得所有属性。但它并没有。至少,它似乎不会出现;

class alarm(object):
    def __init__(self, severity, name, eventId):
        self.severity = severity
        self.name = name
        self.eventId  eventId


class httpalarm(alarm):
    def __init__(self, **kwargs):
        self._dict__.update(kwargs)

现在,当我创建一个警报对象时,我得到了我期望的结果:

a = alarm('Critical', 'Name', '0x800111')

vars(a)
->
{'severity': 'Critical', 'name': 'Name', 'eventId': '0x800111'}

这是预期的。但是当我创建一个httpalarm时:

b = httpalarm(test = 'Test')
vars(b)
->
{'test': 'Test'}

这是出乎意料的。我预计httpalarm b也会设置严重性,名称和eventId属性。

因此,我将警报类设置为使用类属性,而不是实例属性:

class alarm(object):
    severity = 'Warning'
    name = None
    eventId = None

然后再次没有更改为httpalarm我再次测试;

c = httpalarm(test='Test')

vars(c)
->
{'test': 'Test'}

同样,vars没有显示所有其他属性。但是,它们被设置为;

print c.severity
'Warning'

打印继承的属性似乎确实有效。并且还使用dir(c)来显示对象确实返回所有属性

dir(c)
-> 
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'eventId', 'name', 'severity', 'test']

我不确定这里发生了什么。我想创建一个可以继承的警报类,以免我不得不一直定义相同的属性。我想要得到的是:

d = httpalarm(severity = 'Critical', name = 'Name', eventId = '0x800111', test = 'test')

并让httpalarm实例d包含来自alarm的所有属性以及来自其自己的httpalarm类的属性。

编辑: 在Corley Brigman的提交之后,我已经按照预期的方式工作:

class httpalarm(alarm):
    def __init__(self,
                 **kwargs):

        super(httpalarm, self).__init__()
        for k,v in self.__dict__.iteritems():
            if type(v) == tuple:
                setattr(self, k, v[0])

        self.__dict__.update(kwargs)

1 个答案:

答案 0 :(得分:1)

您需要自己调用alarm的构造函数:

class httpalarm(alarm):
    def __init__(self, **kwargs):
        super(httpalarm, self).__init__()
        # Your code here

为什么这里特别需要这个? Python的对象实现与C ++和Java等其他语言有很大不同;它必须对如何创建对象做很多事情。

C ++对象基本上是一个内存结构,附加了一些函数。 Python对象更像是一个附加了一些函数的字典。这是怎么发生的?

在这两种环境中,您可以想象创建(new,但通常在C ++中幕后; __new__作为Python中类的函数)和初始化(C ++中的构造函数,和Python中的__init__)作为两个单独的部分。

在C ++中,由于内存结构对于对象的操作至关重要,因此当您调用new(在高级别)时,系统会为使用正确大小声明的每个属性分配空间。这是静态的 - 您无法动态创建新属性,只能修改声明的属性。请注意,这还要求在您进行子类化时,您还要确切地声明结构的外观 - 因此编译器可以构建正确的内存映像。

然后,您调用构造函数,它实际上根据输入和程序员想要的任何内容初始化值。在许多情况下,如果您对初始化的默认值感到满意,您实际上可以将构造函数保留在C ++中,或者声明它但将其保留为空。

在Python中,由于对象模型更像是一个可变的dict,基类行为('创建一个字典并附加到对象')就是创建该字典。这通常足以满足大多数用法,因此在Python中,您几乎看不到写入__new__函数(*)。

相反,大多数人的默认设置是初始化__init__函数中的变量。重要的是在创建对象之后将其称为。然后,您可以将所需的任何变量设置为您想要的任何数据(无论何种类型)。

关键是在两种情况下,在调用初始化程序之前创建对象。在C ++中,创建创建数据结构。在Python中,对象创建(通常)只是创建一个字典 - 在alarm.__init__httpalarm.__init__的条目中,两个对象看起来就像一个空字典。 init必须创建必要的属性。在C ++中调用基类构造函数也并不罕见,但它在Python中更为常见,因为基类构造函数还创建了子类使用的公共属性。

你可以使用插槽 - 它们更接近C ++的工作方式,但不完全正确。

对于vars - vars仅显示本地属性 - 您在__init__或其他位置设置的属性。当您将它们声明为类变量时,它们将显示在dir中,因为它显示了类属性和本地设置的对象属性,但不显示vars。来自docstring:

vars([object]) -> dictionary

Without arguments, equivalent to locals().
With an argument, equivalent to object.__dict__.

类变量位于object.__class__.__dict__而不是object.__dict__

如果您真的想要这种行为,您实际上可以使用元类,并覆盖__new__函数来创建一些默认属性。它并不常见,但它更像是C ++(据我所知......我也没有做过那么多)。但它有时会完成(通常称为“元编程”或类似的东西),特别是如果你想要动态属性,因为属性(必然)是属性,并且不能动态设置宾语;相反,您使用类工厂,它动态添加所需的属性。