2016-05-20 5 views
0

У меня есть класс, который определяет «будильник», а затем один определяет «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'} 

Опять же, варны не показывают все другие свойства. Однако они устанавливаются как;

print c.severity 
'Warning' 

Печать унаследованного имущества, похоже, сработала. А также с помощью реж (с), чтобы показать объект действительно возвращает все свойства

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 включает все свойства от тревоги, а также свойство от своего класса httpalarm.

Edit: После подачи от Корли 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 «s себя:

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

Почему это особенно необходимо здесь? Реализация объекта Python значительно отличается от других языков, таких как C++ и Java; он должен многое сделать с тем, как создаются объекты.

Объект C++ в основном представляет собой структуру памяти с некоторыми связанными с ней функциями. Объект Python больше похож на словарь с некоторыми связанными с ним функциями. Как это происходит?

В обеих средах, вы можете себе представить создание (new, но обычно за кулисами в C++, __new__ в зависимости от класса в Python), и инициализации (конструктор в C++, и __init__ в Python), как два отдельный штук.

В C++, поскольку структура памяти имеет важное значение для работы объекта, при вызове new (на высоком уровне) система выделяет пространство для каждого атрибута, объявленного с правильным размером. Это статично - вы не можете создавать новые атрибуты «на лету», вы можете изменять только те атрибуты, которые вы указали. Обратите внимание, что это также требует, чтобы при подклассе вы также декларировали, как будет выглядеть структура - поэтому компилятор может создать правильный образ памяти.

Затем вы вызываете конструктор, который фактически инициализирует значения на основе входов и независимо от того, что хочет программист. Во многих случаях вы можете оставить конструктор на C++ или объявить его, но оставить его пустым, если вы довольны значениями по умолчанию, которые инициализируются.

В Python, поскольку объектная модель больше похожа на изменяемый dict, поведение базового класса («создание словаря и прикрепление к объекту») заключается в создании этого словаря. Обычно это достаточно для большинства применений, поэтому в Python вы вряд ли когда-либо увидите функцию __new__, написанную (*).

Вместо этого по умолчанию для большинства людей используется инициализация переменных в функции __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++ (насколько я знаю ... я тоже так не сделал). Но это делается иногда (обычно называемое метапрограммированием или что-то в этом роде), особенно если вы хотите динамические свойства, поскольку свойства (обязательно) являются атрибутом класса и не могут быть динамически установлены на объект; вместо этого вы используете фабрику классов, которая динамически добавляет необходимые атрибуты.

Смежные вопросы