【问题标题】:Repeat methods for object of same class对同一类的对象重复方法
【发布时间】:2017-10-18 10:43:06
【问题描述】:

我想创建两个对象,这样其中一些对象的方法将重复用于其他对象。然后我尝试这样做:

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 获取此类代码。 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 方法可以做到这一点。任何人都可以提供这种方式吗?

【问题讨论】:

  • 如果有更长的循环,期望的行为是什么?它应该只深入一次,还是应该继续直到重复?比如,如果你有一个 A、一个 B 和一个 C,并且 A 代表 B 代表 C 代表 A?
  • 不,程序中应该只有两个Tester类的对象。所以 A 委托给 B,B 委托给 A。所以 A 是 B 的备份,B 是 A 的备份。
  • 请用一个例子来更新你的问题,解释这个估计会有很多方法会重复,所以需要装饰器
  • 谢谢,我添加了例子。
  • 你的两个对象是否总是同一个类的实例(没有子类)?如果是这样,你可以让你的包装器变得非常简单:method(self, *args, **kwargs); method(self.another_tester, *args, **kwargs)

标签: python methods decorator


【解决方案1】:

如果你的一对对象总是同一个类的实例(或者至少,装饰方法的实现没有不同),你可以改变装饰器,让它直接调用另一个实例上的原始方法,而不是通过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

【讨论】:

    猜你喜欢
    • 2021-10-17
    • 2017-12-14
    • 1970-01-01
    • 1970-01-01
    • 2016-07-14
    • 2023-03-19
    • 1970-01-01
    • 2015-04-26
    • 2016-04-20
    相关资源
    最近更新 更多