2017-02-19 3 views
2

(! Эй, ребята, это может быть длинное описание, пожалуйста, немного терпения, спасибо)питон - Доступ к атрибуту класса суперкласса в супер() .__ INIT __()

У меня есть класс Parent со многими свойствами, например, и я всегда передаю dict для инициализации экземпляра. Как это:

info = { 
    "name" : "Bob", 
    "col" : 5, 
    "line" : 10, 
    "type" : "Alien" 
} 

p = Parent(info) 

И в __init__ метод, который я не хочу писать this.property_name = value для каждого свойства Потому что код будет очень долго. Например:

class Parent(object): 

    def __init__(self, kwargs): 
     this.name = kwargs.get("name") 
     this.col = kwargs.get("col") 
     this.line = kwargs.get("line") 
     this.type = kwargs.get("type") 

Так что я хочу использовать функцию итерировать dict, чтобы установить эти свойства экземпляра. Это функция, я писал:

def initialize_properties(instance, names, kwargs): 
    for name in names: 
     setattr(instance, name, kwargs.get(name)) 

Кажется, что мне нужно, чтобы сохранить список имен свойств names где-то, и я решил сохранить его в качестве атрибута класса, потому что я хочу, чтобы мой класс был люди дружелюбный (когда кто-то читает определение класса, он знает, какие свойства экземпляра имеет этот класс). Поэтому я изменил определение своего класса следующим образом:

class Parent(object): 
    props = ("name", "col", "line", "type") 

    def __init__(self, kwargs): 
     initialize_properties(self, self.props, kwargs) 

Это прекрасно работает, когда наследование НЕ рассматривается. Проблема возникает, когда я подкласс Parent:.

class Child(Parent): 
    props = ("foo", "bar") 

    def __init__(self, kwargs): 
     super().__init__(kwargs) 
     initialize_properties(self, self.props, kwargs) 

Я хочу случаи Child наследовать все свойства экземпляра в суперкласса Parent, с некоторыми свойствами экземпляра ребенка конкретным, а также (Вот почему мы используем наследование, ISN» t it?) Поэтому я переписываю атрибут класса props для определения свойств, специфичных для ребенка.

Но это не работает.

info = { 
    "name" : "Bob", 
    "col" : 5, 
    "line" : 10, 
    "type" : "Alien", 
    "foo" : 5, 
    "bar" : 10 
} 

c = Child(info) 

Instance c имеет только c.foo и c.bar определены и установлены, в то время как c.name не определен.

После некоторого копания я обнаружил, что, когда Parent.__init__(self, kwargs) вызывается через функцию super(), то self переданный аргумент класса Child, поэтому self.props вычисляет Child.props.

Если я хочу, чтобы установить свойство экземпляра в Parent.props, я должен явно использовать Parent.props в Parent.__init__(self, kwargs), что:

class Parent(object): 
    props = ("name", "col", "line", "type") 

    def __init__(self, kwargs): 
     initialize_properties(self, Parent.props, kwargs) 

Это позволит решить эту проблему, но я думаю, что это не очень «чистый», потому что вам нужно жестко закодировать имя класса Parent.

Так что мой вопрос: есть ли способ для определить текущий класс и получить доступ к его атрибутам класса, когда вы вызываете цепочку из super().__init__() для инициализации экземпляра подкласса?

+2

Это похоже на большую работу, чтобы избежать «this.property_name = value» для каждого свойства, потому что код будет очень длинным »... –

ответ

0

Вы могли бы реализовать метод, который собирающий props от всех supeclasses и использовать его в __init__:

class Parent(object): 
    props = ("name", "col", "line", "type") 

    def __init__(self, **kwargs): 
     def __init__(self, kwargs): 
     initialize_properties(self, self.get_props(), kwargs) 

    def get_props(self): 
     return sum((getattr(k, 'props',()) for k in self.__class__.mro()),()) 

Теперь вы можете просто определить подклассы, как вы хотели. Вы даже не должны переопределить конструктор:

class Child(Parent): 
    props = ("foo", "bar") 

Это, как говорится, вы утверждаете, вы хотите, чтобы классы людей дружелюбным. Если человек читает свой класс ребенка, они будут рады прочитать:

class Child(Parent): 
    props = 'foo', 'bar', 'name', 'col', 'line', 'type' 

и иметь весь класс props доступны в одном месте.

0

self.props атрибут экземпляра первой ссылки, атрибут класса и атрибут класса родителя, ...

Определяя Child.props, self.props ссылается на атрибут класса Child.props, останавливаясь там, не выполняя поиск в родительском классе.

Как насчет сделать Child.props также включают родителей props?

class Child(Parent): 
    props = Parent.props + ("foo", "bar") # <--- 

    def __init__(self, kwargs): 
     super().__init__(kwargs) 
     initialize_properties(self, self.props, kwargs) 
0

Чтобы ответить вам вопрос

Есть ли способ обнаружить текущий класс и доступ к его атрибутам класса , когда вы вызываете цепь супер(). init()

На мой взгляд, никоим образом.

Однако, вы можете использовать декоратора, чтобы упростить код

def add_props(names, cls=None): 
    if cls is None: 
     return lambda cls:add(names, cls) 
    for c in cls.__bases__: 
     names.extend(c.props) 
    names = list(set(names)) 
    cls.props = names 
    return cls 


class A: 
    props = ['a','b'] 


@add_props(names=['c']) 
class B(A): 
    pass 

выход:

In [69]: B.props 
Out[69]: ['a', 'b', 'c'] 

Но, он должен сказать, что если вы хотите дружественно, лучший способ я думаю, что не используется props, просто напишите код в вашем методе __init__.

class Root: 
    def __init__(self, a=None, b=None): 
     self.a = a 
     self.b = b 


class Child(Root): 
    def __init__(self, c=None, d=None, **kwargs): 
     self.c = c 
     self.d = d 
     super().__init__(**kwargs) 

Вы также можете иметь удобство пройти Dict, как вам нравится

data = {'a': 1} 
c = Child(**data) 

И это не только дружественным к человеку, но и дружественным для большинства редакторов.

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