Я должен найти изящный способ сделать 2 вида MixIns.
Во-первых:
class A(object):
def method1(self):
do_something()
Теперь, a MixInClass
должен сделать method1
сделайте это: do_other()
-> A.method1()
-> do_smth_else()
- т.е. в основном "перенесите" более старую функцию. Я вполне уверен, там должен существовать хорошее решение этого.
Во-вторых:
class B(object):
def method1(self):
do_something()
do_more()
В этом случае я хочу MixInClass2
смочь ввестись между do_something()
и do_more()
, т.е.: do_something()
-> MixIn.method1
-> do_more()
. Я понимаю, что, вероятно, это потребовало бы изменения class B
- это в порядке, просто ища самые простые способы достигнуть этого.
Это довольно тривиальные проблемы, и я на самом деле решил их, но мое решение испорчено.
Fisrt один при помощи self._old_method1 = self.method1(); self.method1() = self._new_method1();
и запись _new_method1()
это звонит в _old_method1()
.
Проблема: несколько MixIns все переименуют к _old_method1, и это неэлегантно.
Второй MixIn каждый был решен путем создания фиктивного метода call_mixin(self): pass
и введение его между вызовами и определением self.call_mixin()
. Снова неэлегантный и повредится на нескольких MixIns..
Какие-либо идеи?
Благодаря Boldewyn я нашел изящное решение сначала один (я имею, забыл, что можно создать декораторов на лету, не изменяя исходный код):
class MixIn_for_1(object):
def __init__(self):
self.method1 = self.wrap1(self.method1)
super(MixIn_for_1, self).__init__()
def wrap1(self, old):
def method1():
print "do_other()"
old()
print "do_smth_else()"
return method1
Все еще ища идеи для второй (эта идея не будет соответствовать, так как я должен ввести в старом методе, не снаружи, как в этом случае).
Решение для второго ниже, заменяя "pass_func" с lambda:0
.
Вот еще один способ реализовать MixInClass1, MixinClass2:
Декораторы полезны, когда вам нужно обернуть множество функций. Поскольку MixinClass1
должен содержать только одну функцию, я думаю, что для monkey-patch это более понятно:
Использование двойного подчеркивания для __ old_method1
и __ method1
играет полезную роль. роль в MixInClass1
.Из-за соглашения Python об изменении имен использование двойного подчеркивания локализует эти атрибуты в MixinClass1
и позволяет вам использовать те же имена атрибутов для других смешанных классов, не вызывая нежелательных конфликтов имен.
class MixInClass1(object):
def __init__(self):
self.__old_method1,self.method1=self.method1,self.__method1
super(MixInClass1, self).__init__()
def __method1(self):
print "pre1()"
self.__old_method1()
print "post1()"
class MixInClass2(object):
def __init__(self):
super(MixInClass2, self).__init__()
def method1_hook(self):
print('MixIn method1')
class Foo(MixInClass2,MixInClass1):
def method1(self):
print "do_something()"
getattr(self,'method1_hook',lambda *args,**kw: None)()
print "do_more()"
foo=Foo()
foo.method1()
Я думаю, это можно сделать вполне по-питоновски, используя декораторы. (PEP 318, тоже)