Python class 覆盖内部方法的装饰器

Python class decorator that overrides internal method

我正在尝试编写一个装饰器,它可用于在继承过程中覆盖方法,但在外部。 类似于:

class A:
   def some_method(self):
       print('does stuff')

def override(method):
    # override decorator
    ....

def some_method_override():
    print('does other stuff')

@override(method, some_method_override)
class B:
    #overridden

a = A()
b = B()
a.some_method() # prints 'does stuff'
b.some_method() # prints 'does other stuff'

如果有人能就此分享一些想法,那就太好了!

以下是我将如何根据用例解决问题;

  1. 用于测试 - 如果您尝试动态覆盖方法,我会查看模拟库。这是资源 - https://docs.python.org/3/library/unittest.mock.html

  2. FOR SEPARATE CLASS - 如果它是 class-wide 变化,我会选择覆盖原始方法的子 class;这将使您的代码更加明确

    class A:
        def some_method(self):
            print('do_stuff_a')
    
    class B(A):
        def some_method(self):
            print('do_stuff_b')
    
    a = A()
    a.some_method() # print 'do_stuff_a'
    b = B()
    a.some_method() # prints 'do_stuff_b'
    
  3. 针对特定情况 - 如果您只希望这种行为有时发生,我会使用状态观察者代码模式 - 这是一个示例

    class A:
        def __init__(self)
            self._use_method_a = True
    
        def use_method_a(self, use_method_a):
            self._use_method_a = use_method_a
    
        def some_method(self):
            if self._use_method_a:
                return self._method_a()
            else:
                return self._method_b()
    
        def _method_a(self):
            print('do_stuff_a')
    
        def _method_b(self):
            print('do_other_stuff_b')
    
    a = A()
    a.some_method() # print 'do_stuff_a'
    a.use_method_a(False) 
    a.some_method() # prints 'do_other_stuff_b'
    

正如其他人在评论中提到的,我认为这里不需要装饰器。这只是 class 属性分配的问题。

定义 class 时不会发生继承;来自父项的方法不会“引入”到子项 class。相反,它发生在属性查找期间。如果未定义 B.some_method,则使用 A.some_method 的值。因此,要覆盖 parent-class 方法,您只需提供所需 class 属性的定义即可。方法只是具有 function.

类型值的 class 属性
class A:
   def some_method(self):
       print('does stuff')


def some_method_override(self):
    print('does other stuff')


class B(A):
    some_method = some_method_override

a = A()
b = B()
a.some_method() # prints 'does stuff'
b.some_method() # prints 'does other stuff'

如果你确实想要一个装饰器,它就像

def override(old: str, new: Callable):
    def _(cls):
        setattr(cls, old, new)
        return cls
    return _


def some_method_override(self):
    print('does other stuff')


class A:
   def some_method(self):
       print('does stuff')


@override('some_method', some_method_override)
class B(A):
    pass