2016-05-20 156 views
0

我有一个类定义了'alarm',然后一个定义了'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属性。没有改变httpalarm我再测试一次

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

然后;:

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

c = httpalarm(test='Test') 

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

此外,变量不显示所有其他属性。但是,他们正在被设定为;

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实例ð包括报警的所有属性,以及其自己的httpalarm类的属性。

编辑: 继从科利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

您需要自行调用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中,由于对象模型更像是一个可变字典,因此基类行为('创建字典并附加到对象')是创建该字典。对于大多数用途来说,这通常是足够的,所以在Python中,你几乎不会看到用(*)写的函数。

相反,大多数人的默认设置是初始化__init__函数中的变量。重要的是这个被称为之后对象被创建。然后,你可以设置你想要的任何变量,无论你想要的任何数据类型。

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

您可以使用插槽 - 它们更接近于C++的工作方式,但不完全如此。

对于vars - vars只显示当地属性 - 你在__init__或其他地方设置的。当你将它们声明为类变量时,它们将显示在dir中,因为它显示了类属性和本地设置的对象属性,但不是vars。从文档字符串:

vars([object]) -> dictionary 

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

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

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