2013-04-24 4 views
0

У меня есть один ко многим структуры наследования классов следующим образом:простирающиеся все подклассы суперкласса

class SuperClass: 
    def func1(): 
    print 'hello' 

    def func2(): 
    print 'ow' 

class SubClass1(SuperClass): 
    def func1(): 
    print 'hi' 

class SubClass2(SuperClass): 
    def func1(): 
    print 'howdy' 

... 

Я хочу, чтобы добавить функциональность к классу А, так что я могу использовать его при создании классов В и С (и т.д.), но я не могу редактировать код для класса А напрямую. Мой текущий раствор:

def func3(): 
    print 'yes!' 

SuperClass.func3 = func3 

Есть ли лучший и/или более питонический способ достичь этого?

+2

Почему функциональность должна быть добавлена ​​к класс 'A'? Разве это не просто простая старая функция в каком-то другом пространстве имен? «Забивание * всего * в классы», безусловно, не является пифоническим. – millimoose

+0

Да, пожалуйста, объясните свой пример использования – jamylak

+1

Кроме того, если вы используете B и C, вы можете добавить тип посредника, который расширяет суперкласс с требуемой функциональностью, и вместо этого B и C расширят этот класс – mdgeorge

ответ

1

Это называется «monkeypatching», и в некоторых случаях вполне разумно.

Например, если вам нужно использовать чужой код (который вы не можете изменить), который зависит от SuperClass, и вам нужно изменить поведение этого кода, ваш единственный реальный выбор - заменить методы на SuperClass.


Однако, в вашем случае, по-видимому, нет веских оснований для этого. Вы определяете все подклассы SuperClass, так почему бы просто не добавить еще один класс между ними?

class Intermediate(SuperClass): 
    def func3(): 
     pass 

class SubClass1(Intermediate): 
    def func1(): 
     print 'hi' 

Это не достаточно хорош для «функциональность, которая должна была в SuperClass, но не было», если другой код, который вы не можете контролировать потребности, функциональность ... но когда это только код что нужно что функциональность, это так же хорошо, и намного проще.


Если даже подклассы не находятся под вашим контролем, часто вы можете просто получить новый класс от каждого, что является. Например:

class Func3Mixin(object): 
    def func3(): 
     pass 

class F3SubClass1(SubClass1, Func3Mixin): 
    pass 

class F3SubClass2(SubClass2, Func3Mixin): 
    pass 

Теперь вы просто построить экземпляры F3SubClass1 вместо SubClass1. Код, который ожидал экземпляр SubClass1, может использовать только F3SubClass1. И утиная печать на Python делает такое «ориентированное на микширование программирование» особенно простым: внутри реализации Func3Mixin.func3 вы можете использовать атрибуты и методы SuperClass, несмотря на то, что Func3Mixin сам по себе не статически связан с SuperClass, потому что вы знаете, что любой объект времени выполнения, который является Func3Mixin, также будет SuperClass.


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


Кроме того, стоит отметить, что ни один из классов не являются на самом деле можно использовать как списанную любую попытку вызвать любого из методов поднимут TypeError, потому что они отсутствуют в self аргумент. Но так, как вы обеимели в func3, он потерпит неудачу точно так же, как func1. (И то же самое верно для альтернатив, которые я набросал выше.)


Наконец, все ваши классы здесь классические классы, а не новый стиль, потому что вы забыли сделать SuperClass наследовать от object. Если вы не можете изменить SuperClass, конечно, это не ваша вина, но вы все равно можете ее исправить, сделав ваши подклассы (или Intermediate) умножить наследование с object и SuperClass. (Если вы обращали внимание: да, это означает, что вы можете смешивать в стиле нового стиля. Хотя под обложками вы должны понимать метаклассы, чтобы понять, почему.)

+0

Цените свои комментарии. Кстати, у меня тоже нет контроля над «SubClass». Я хочу добавить функциональность в «SuperClass», чтобы объект «SubClass1», или «SubClass2» или любой другой подкласс мог использовать этот код. – 4myle

+0

Можете ли вы создать свои собственные подклассы каждого подкласса? (Я не хочу, чтобы это звучало _too_ отрицательное. Вам следует избегать «обезьянья патчи», когда можно разумно избежать ... но в любом случае, когда альтернативы являются неуклюжими или даже хакерами и т. Д., Обязательно используйте его.) – abarnert

+1

«Monkeypatching» также имеет более почтенное название «Аспектно-ориентированное программирование». – Apalala

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