Как применить класс миксина к базовому классу старого стиля

Я написал класс миксина, предназначенный для наложения поверх класса нового стиля, например, через

class MixedClass(MixinClass, BaseClass):
    pass

Как проще всего применить этот миксин к классу в старом стиле? Он использует вызов super в своем методе __init__, так что, по-видимому, это (?) должно измениться, но в противном случае я хотел бы внести как можно меньше изменений в MixinClass. Я должен быть в состоянии получить подкласс, который вносит необходимые изменения.

Я рассматриваю возможность использования декоратора класса поверх класса, полученного из BaseClass, например.

@old_style_mix(MixinOldSchoolRemix)
class MixedWithOldStyleClass(OldStyleClass)

где MixinOldSchoolRemix является производным от MixinClass и просто повторно реализует методы, использующие super, чтобы вместо этого использовать переменную класса, содержащую класс, с которым она смешана, в данном случае OldStyleClass. Эта переменная класса будет установлена ​​old_style_mix как часть процесса микширования.

old_style_mix просто обновит словарь классов, например. MixedWithOldStyleClass с содержимым словаря класса mixin (например, MixinOldSchoolRemix).

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


person intuited    schedule 01.09.2010    source источник
comment
Буду ли я не в порядке, если предложу преобразовать класс старого стиля в класс нового стиля?   -  person aaronasterling    schedule 01.09.2010
comment
@aaronasterling: Если бы я мог заставить его задним числом обновляться во всех установках стандартной библиотеки, я бы обязательно это сделал.   -  person intuited    schedule 01.09.2010


Ответы (1)


Эта переменная класса будет установлена ​​old_style_mix как часть процесса микширования.

... Я предполагаю, что вы имеете в виду: "... в классе, который он украшает...", а не "в классе, который является его аргументом" (последнее было бы катастрофой).

old_style_mix просто обновит словарь классов, например. MixedWithOldStyleClass с содержимым словаря класса mixin (например, MixinOldSchoolRemix).

Плохо - информация, которую MixinOldSchoolRemix выводит из MixinClass, например, нет в словаре первого. Таким образом, old_style_mix должен использовать другую стратегию: например, создать новый класс (который, я считаю, должен быть в новом стиле, потому что старые не принимают новые классы как __bases__ ) с соответствующей последовательностью оснований, а также соответствующим образом настроенным словарем.

Это разумная стратегия?

С вышеуказанными оговорками.

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

...но примеси с классами, которые никогда не предназначались для приема примесей, определенно не являются распространенным шаблоном проектирования, так что проблема вообще не распространена (я не помню, чтобы видел ее хоть раз в много лет с тех пор, как родились классы нового стиля, и я активно консультировал, преподавал продвинутые классы и помогал людям с проблемами Python в течение многих из этих лет, а также сам занимался разработкой программного обеспечения - я действительно сталкивался с любая «достаточно распространенная» проблема, которая может возникнуть у людей с функциями, которые существуют достаточно давно!-).

Вот пример кода того, что может сделать ваш декоратор класса (если вы предпочитаете использовать его в декораторе класса, а не прямо в строке...):

>>> class Mixo(object):
...   def foo(self):
...     print 'Mixo.foo'
...     self.thesuper.foo(self)
... 
>>> class Old:
...   def foo(self):
...     print 'Old.foo'
... 
>>> class Mixed(Mixo, Old):
...   thesuper = Old
... 
>>> m = Mixed()
>>> m.foo()
Mixo.foo
Old.foo

Если вы хотите построить Mixed под предполагаемым именем/привязкой Mixo в вашем декораторе, вы можете сделать это с помощью вызова type или установки Mixed.__name__ = cls.__name__ (где cls — класс, который вы украшаете). Я думаю, что последний подход проще (предупреждение, непроверенный код - приведенный выше интерактивный сеанс оболочки является реальным, но я не тестировал следующий код):

def oldstylemix(mixin):
    def makemix(cls):
        class Mixed(mixin, cls):
            thesuper = cls
        Mixed.__name__ = cls.__name__
        return Mixed
    return makemix
person Alex Martelli    schedule 01.09.2010