2016-06-19 5 views
0

Допустим, у нас есть класс A, класс B, который наследуется от A и классов C, D и E, которые наследуют от B.поля во всех подклассов класса

Мы хотим, чтобы все эти классы имели атрибут _f, инициализированный значением по умолчанию, и мы хотим, чтобы этот атрибут изменялся и имел отдельное значение для каждого экземпляра класса, то есть он не должен быть статическим, постоянное значение A, используемое всеми подклассами.

Один из способов сделать это, чтобы определить _f в способе А в __init__, а затем полагаться на этот метод в подклассах:

class A: 
    def __init__(self): 
     self._f = 'default_value' 

class B(A): 
    def __init__(self): 
     super(B, self).__init__() 

class C(B): 
    def __init__(self): 
     super(C, self).__init__() 

Есть ли хороший Pythonic способ избежать этого, и, возможно, избегать использования метаклассов ?

+2

Обратите внимание, что если все реализации подкласса являются вызовом реализации суперкласса, вы можете оставить их вне. 'class B (A): pass' будет работать нормально. И вы ищете атрибут * class * или обычный атрибут * экземпляра *? Не могли бы вы привести менее абстрактный пример? – jonrsharpe

+0

Зависит, если поле '_f' предназначено для обращения к изменяемому или неизменяемому типу. – Aya

+0

Предполагается, что '_f' должно быть полем класса или поле экземпляра? – schwobaseggl

ответ

0

Если вы хотите упростить конструкторы подкласса, исключив необходимость вызова конструктора базового класса, но все же сможете переопределить значение по умолчанию в подклассах, существует общая парадигма использования того факта, что Python вернет значение класса для атрибута, если он не существует в экземпляре.

Используя несколько более конкретный пример, вместо того, чтобы делать ...

class Human(object): 

    def __init__(self): 
     self._fingers = 10 

    def __repr__(self): 
     return 'I am a %s with %d fingers' % (self.__class__.__name__, self._fingers) 


class MutatedHuman(Human): 

    def __init__(self, fingers): 
     super(MutatedHuman, self).__init__() 
     self._fingers = fingers 


print MutatedHuman(fingers=11) 
print Human() 

... Вы можете использовать ...

class Human(object): 

    _fingers = 10 

    def __repr__(self): 
     return 'I am a %s with %d fingers' % (self.__class__.__name__, self._fingers) 


class MutatedHuman(Human): 

    def __init__(self, fingers): 
     self._fingers = fingers 


print MutatedHuman(fingers=11) 
print Human() 

... оба из которых выход ...

I am a MutatedHuman with 11 fingers 
I am a Human with 10 fingers 

важный момент в том, что линия self._fingers = fingers во втором примере не перезаписывает значение по умолчанию как таковые t по классу Human, но просто скрывает его, если ссылается на self._fingers.

Немного волосатый, когда переменная относится к изменяемому типу, например списку. Вы должны быть осторожны, чтобы не выполнять операцию по значению по умолчанию, которое изменит его, хотя по-прежнему безопасно делать self.name = value.

В этом аспекте, как правило, это приводит к меньшему количеству строк кода, чем другие подходы, обычно это хорошая вещь (tm).

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