对同一类的对象重复方法

时间:2017-05-18 14:36:39

标签: python methods decorator

我想创建两个对象,以便为其他对象重复某些对象的方法。然后我尝试这样做:

def backup(method):
    def wrapper(self, *args, **kwargs):
        method(self, *args, **kwargs)
        getattr(self.another_tester, method.__name__)(*args, **kwargs)
    return wrapper

class Tester():
    def __init__(self, name):
        self.name = name
    def select_backup(self, tester):
        self.another_tester = tester
    @backup
    def foo1(self, stop=False):
        print("I am tester {}, do method foo1".format(self.name))
    @backup
    def foo2(self, stop=False):
        print("I am tester {}, do method foo2".format(self.name))
    @backup
    def foo3(self, stop=False):
        print("I am tester {}, do method foo3".format(self.name))

tester1 = Tester("A")
tester2 = Tester("B")
tester1.select_backup(tester2)
tester2.select_backup(tester1)
tester1.foo1()
tester2.foo2()
tester1.foo3()

我得到RuntimeError: maximum recursion depth exceeded while calling a Python object这样的代码。 class Tester有很多不同的方法(foo1,foo2,foo3,...),我想backup(重复)每个方法。所以我使用装饰。

我可以更改装饰器:

def backup(method):
    def wrapper(self, *args, **kwargs):
        method(self, *args, **kwargs)
        try:
            kwargs["stop"]
        except KeyError:
            getattr(self.another_tester, method.__name__)(stop=True, *args, **kwargs)
    return wrapper

它的工作,但我认为还有更多的pythonic方式。任何人都可以提供这样的方式吗?

1 个答案:

答案 0 :(得分:0)

如果你的对象总是同一个类的实例(或者至少,从来没有对装饰方法的不同实现),你可以更改装饰器,使它直接调用另一个实例上的原始方法,而不是通过getattr获取装饰版本:

def backup(method):
    def wrapper(self, *args, **kwargs):
        method(self, *args, **kwargs)
        method(self.another_tester, *args, **kwargs)
    return wrapper

如果您希望能够支持不同类的对象(以及不同的方法实现),那么事情需要更复杂一些。您可以将对原始未修饰方法的引用保存为包装函数的属性,然后在需要时查找:

def backup(method):
    def wrapper(self, *args, **kwargs):
        method(self, *args, **kwargs)
        other_method = getattr(self.another_tester, method.__name__).orig_method
        other_method(self.another_tester, *args, **kwargs)
    wrapper.orig_method = method
    return wrapper