类装饰器实际上获取了已经构建的类 - 并实例化(作为类对象)。它可以对它的 dict 执行更改,甚至可以用其他装饰器包装它的方法。
但是,这意味着该类已经设置了它的基础 - 通常不能更改这些基础。这意味着您必须在某些情况下重建装饰器代码中的类。
但是,如果类的方法使用无参数的super 或__class__ 单元格变量,则这些已在成员函数中设置(在 Python 3 中与未绑定方法相同),您不能只创建一个新类并将这些方法设置为新类的成员。
因此,可能有一种方法,但它并非易事。正如我在上面的评论中指出的那样,我想了解您希望通过此实现的目标,因为可以将 base 类放在类声明本身上,而不是在装饰器配置。
我已经制作了一个函数,如上所述,它创建一个新类,“克隆”原始类,并且可以重新构建所有使用 __class__ 或 super 的方法:它返回功能性的新类与原来的相同,但交换了碱基。如果按要求在装饰器中使用(包括装饰器代码),它将简单地更改类库。它不能处理修饰方法(classmethod 和 staticmethod 除外),并且不关心命名细节 - 例如方法的 qualnames 或 repr。
from types import FunctionType
def change_bases(cls, bases, metaclass=type):
class Changeling(*bases, metaclass=metaclass):
def breeder(self):
__class__ #noQA
cell = Changeling.breeder.__closure__
del Changeling.breeder
Changeling.__name__ = cls.__name__
for attr_name, attr_value in cls.__dict__.items():
if isinstance(attr_value, (FunctionType, classmethod, staticmethod)):
if isinstance(attr_value, staticmethod):
func = getattr(cls, attr_name)
elif isinstance(attr_value, classmethod):
func = attr_value.__func__
else:
func = attr_value
# TODO: check if func is wrapped in decorators and recreate inner function.
# Although reaplying arbitrary decorators is not actually possible -
# it is possible to have a "prepare_for_changeling" innermost decorator
# which could be made to point to the new function.
if func.__closure__ and func.__closure__[0].cell_contents is cls:
franken_func = FunctionType(
func.__code__,
func.__globals__,
func.__name__,
func.__defaults__,
cell
)
if isinstance(attr_value, staticmethod):
func = staticmethod(franken_func)
elif isinstance(attr_value, classmethod):
func = classmethod(franken_func)
else:
func = franken_func
setattr(Changeling, attr_name, func)
continue
setattr(Changeling, attr_name, attr_value)
return Changeling
def decorator(bases):
if not isinstance(base, tuple):
bases = (bases,)
def stage2(cls):
return change_bases(cls, bases)
return stage2