Заставить декоратор расширять статическое поле в унаследованном классе, даже если это явно не переопределено

Я работаю над написанием декоратора для использования в унаследованном классе, и этот декоратор должен добавить некоторые значения в список, который является полем базового класса. Проблема, которую я обнаружил, заключается в том, что если в определении класса явно не указано это поле, декоратор вместо этого изменяет базовый класс, который, в свою очередь, добавляет значения ко всем другим классам, которые также наследуются от этого класса. Кажется, что поля не определяются в классе, а вместо этого манипулируют полями в базовом классе. Есть ли способ заставить унаследованные классы иметь свои собственные изменяемые поля (которые начинаются с того же значения, что и базовые поля), которые не влияют на значение полей базового класса?

Конечно, я мог бы найти способы обойти это, не делая то, что я делаю, но мне интересно, есть ли способ заставить то, что я хочу делать, предпочтительно путем изменения декоратора. В дополнение к решению было бы здорово объяснить, почему это так и чего я не понимаю в python, наследовании статических полей и декораторах!

Ниже я привел основные случаи. Обратите внимание, что строки this prints отображаются, если классы Extension# используются по отдельности, а не рядом друг с другом, как показано.

def add_values(cls):
    cls.my_list.append(1)
    return cls

class Base(object):
    my_list = []

### in the following case, the definition of Base actually changes
@add_values
class Extension1(Base):

    def append_1(self):
        self.my_list.append(1)
        print(self.my_list) ### this prints [1, 1]
        print(Base.my_list) ### this prints [1, 1]


### in this case, the definition of Base is fine and it only modifies
### the field on this class definition, which is what I'd expect.
@add_values
class Extension2(Base):
    my_list = []

    def append_1(self):
        self.my_list.append(1)
        print(self.my_list) ### this prints [1, 1]
        print(Base.my_list) ### this prints []

person RutledgePaulV    schedule 04.10.2014    source источник


Ответы (1)


Классы не делают копии значений, которые они наследуют от своих базовых классов. Это просто система поиска атрибутов, которая ищет их там, где они были определены ранее. Что вам, вероятно, следует сделать, так это изменить вашу мутацию переменной класса my_list на немутирующую версию:

def add_values(cls):
    cls.my_list = cls.my_list + [1]  # like cls.my_list.append(1), but makes a new list
    return cls

Это создает новый список с добавленным 1 и связывает его с add_values, независимо от того, украшаете ли вы базовый класс или производный.

person Blckknght    schedule 04.10.2014