在装饰器中扩展 class in Python

Extending a class in Python inside a decorator

我正在使用装饰器来扩展某些 classes 并向它们添加一些功能,如下所示:

def useful_stuff(cls):
  class LocalClass(cls):
    def better_foo(self):
      print('better foo')
  return LocalClass

@useful_stuff
class MyClass:
  def foo(self):
    print('foo')

不幸的是,由于非全局 LocalClass

MyClass 不再是 pickleable
AttributeError: Can't pickle local object 'useful_stuff.<locals>.LocalClass'

您需要设置元数据,使子class看起来像原来的:

def deco(cls):
    class SubClass(cls):
        ...
    SubClass.__name__ = cls.__name__
    SubClass.__qualname__ = cls.__qualname__
    SubClass.__module__ = cls.__module__
    return SubClass

类 通过使用他们的模块和 qualname 来 pickled 来记录在哪里可以找到 class。您的 class 需要在与原始 class 相同的位置找到,如果它没有被装饰的话,所以 pickle 需要看到相同的模块和 qualname。这类似于 funcutils.wraps 对修饰函数所做的。

但是,将新方法直接添加到原始 class 而不是创建子方法可能会更简单且更不容易出错 class:

def better_foo(self):
    print('better_foo')

def useful_stuff(cls):
    cls.better_foo = better_foo
    return cls