【问题标题】:python - dynamically overriding a method at instance level and 'updating' all referencespython - 在实例级别动态覆盖方法并“更新”所有引用
【发布时间】:2020-07-01 09:59:22
【问题描述】:

我想用 B 类中的方法覆盖 A 类实例的方法,但以某种方式对实例的旧方法的所有引用(在覆盖方法之前进行)然后“链接”到新的一个。在代码中:

import types

class A:
    def foo(self):
        print('A')

class B:
    def foo(self):
        print('B')

class C:
    def __init__(self, a):
        self.func = a.foo

    def do_something(self):
        self.func()


a = A()
c = C(a)


method_name = 'foo'  # it has to be dynamic
new_method = getattr(B, method_name)
setattr(a, method_name, types.MethodType(new_method, a))


c.do_something()  # still prints A, I want it to print B now

我希望 c.func 在设置 a 的属性后保留类 B 的新方法(不对 c 对象做任何事情)。

有没有办法设置实例 a 的属性,以便所有之前进行的引用都引用新方法?

对不起,如果这个问题有点愚蠢,我不太喜欢这个。

【问题讨论】:

  • 请注意,要使其工作,c 必须知道a,而不仅仅是a.foo。这是您的设置可接受的更改吗?
  • 并非总是如此。但在某些情况下,它可能会有所帮助。这取决于实现。

标签: python setattr


【解决方案1】:

你可以这样做,例如:

...
def retain(foo):
    return lambda *args, **kwargs: getattr(foo.__self__, foo.__name__)(*args, **kwargs)

class C:
    def __init__(self, a):
        self.func = retain(a.foo)
...

【讨论】:

  • 哦,这真是太好了!太感谢了。我会尝试一些东西,但对我来说似乎很可靠。
  • 我刚刚发现了一个小问题。在我的软件的其他地方,我尝试访问引用的序列化方法的名称 (c.func.__name__),它现在只返回 。有什么想法吗?
【解决方案2】:

只是添加到亚历克斯的答案。 就我而言,所描述的动态部分来自对序列化和反序列化的需要。为了序列化某些方法引用,我曾经使用func.__name__

但是,c.func.__name__ 只会使用 Alex 的方法返回 <lambda>。我通过创建一个使用保留函数但单独存储方法名称的可调用类来防止这种情况发生,这在我的情况下就足够了,因为它只是我需要序列化的一些特定引用。

def retain(foo):
    return lambda *args, **kwargs: getattr(foo.__self__, foo.__name__)(*args, **kwargs)

class M:
    def __init__(self, method):
        self.method_name = method.__name__
        self.method = retain(method)

    def __call__(self, *args, **kwargs):
        self.method(*args, **kwargs)

class A:
    def foo(self):
        print('A')

class B:
    def foo(self):
        print('B')

class C:
    def __init__(self, method):
        self.func = M(method)

    def do_something(self):
        self.func()

a = A()
c = C(a.foo)
setattr(a, method_name, types.MethodType(getattr(B, 'foo'), a))
c.do_something()  # now prints B

# when serializing
method_name = c.func.method_name

【讨论】:

    猜你喜欢
    • 2010-09-28
    • 2019-09-19
    • 2011-01-04
    • 2019-12-16
    • 2012-06-29
    • 2012-07-19
    • 2022-01-02
    • 1970-01-01
    • 2016-08-04
    相关资源
    最近更新 更多