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

时间:2021-07-28 22:49:27

标签: python oop inheritance overriding decorator

我正在尝试编写一个装饰器,该装饰器可用于在继承期间但在外部覆盖方法。 类似的东西:

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'

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

2 个答案:

答案 0 :(得分:0)

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

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

  2. 对于单独的类 - 如果是类范围的更改,我会使用覆盖原始方法的子类;这将使您的代码更加明确

    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'
    

答案 1 :(得分:0)

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

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

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
相关问题