Оптимальный способ расширения атрибута класса в подклассах
Скажем, у меня есть следующий класс
class Parent(object):
Options = {
'option1': 'value1',
'option2': 'value2'
}
И подкласс под названием Child
class Child(Parent):
Options = Parent.Options.copy()
Options.update({
'option2': 'value2',
'option3': 'value3'
})
Я хочу иметь возможность переопределять или добавлять параметры в дочернем классе. Решение, которое я использую, работает. Но я уверен, что есть лучший способ сделать это.
ИЗМЕНИТЬ
Я не хочу добавлять параметры как атрибуты класса, потому что у меня есть другие атрибуты класса, которые не являются параметрами, и я предпочитаю хранить все варианты в одном месте. Это всего лишь простой пример, реальный код более сложный.
Ответы
Ответ 1
Один из способов - использовать аргументы ключевого слова dict для указания дополнительных ключей:
Parent.options = dict(
option1='value1',
option2='value2',
)
Child.options = dict(Parent.options,
option2='value2a',
option3='value3',
)
Если вы хотите стать более привлекательным, то используя протокол дескриптора, вы можете создать прокси-объект, который будет инкапсулировать поиск. (просто пройдите владельца.__ mro__ от атрибута owner к методу __get __ (self, instance, owner)). Или даже причудливый, пересекающийся с территорией, возможно, не очень хорошей идеей, метаклассами/декораторами класса.
Ответ 2
Семантически эквивалентный вашему коду, но, возможно, опрятный:
class Child(Parent):
Options = dict(Parent.Options,
option2='value2',
option3='value3')
Помните, что "жизнь лучше без фигурных скобок", и вызывая явно dict
, вы часто можете избежать брекетов (и дополнительных кавычек вокруг клавиш, которые являются константами, подобными идентификатору).
Подробнее см. http://docs.python.org/library/stdtypes.html#dict - бит ключа - "Если ключ указан как в аргументе positional, так и как ключевое слово аргумент, значение, связанное с ключевым словом, сохраняется", т.е. ключевое слово args переопределяет ассоциации ключевого значения в позиционном arg, так же как метод update
позволяет вам переопределить их).
Ответ 3
Подумав об этом больше, и благодаря предложению @SpliFF это то, с чем я столкнулся:
class Parent(object):
class Options:
option1 = 'value1'
option2 = 'value2'
class Child(Parent):
class Options(Parent.Options):
option2 = 'value2'
option3 = 'value3'
Я все еще готов к лучшим решениям.
Ответ 4
Почему бы просто не использовать атрибуты класса?
class Parent(object):
option1 = 'value1'
option2 = 'value2'
class Child(Parent):
option2 = 'value2'
option3 = 'value3'
Ответ 5
class ParentOptions:
option1 = 'value1'
option2 = 'value2'
class ChildOptions(ParentOptions):
option2 = 'value2'
option3 = 'value3'
class Parent(object):
options = ParentOptions()
class Child(Parent):
options = ChildOptions()
Ответ 6
Вот способ использования метакласса
class OptionMeta(type):
@property
def options(self):
result = {}
for d in self.__mro__[::-1]:
result.update(getattr(d,'_options',{}))
return result
class Parent(object):
__metaclass__ = OptionMeta
_options = dict(
option1='value1',
option2='value2',
)
class Child(Parent):
_options = dict(
option2='value2a',
option3='value3',
)
print Parent.options
print Child.options