Оптимальный способ расширения атрибута класса в подклассах

Скажем, у меня есть следующий класс

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