gpt4 book ai didi

python - 在大量使用元类的库中,如何避免因元类冲突而烦扰用户?

转载 作者:太空宇宙 更新时间:2023-11-04 04:35:24 32 4
gpt4 key购买 nike

我正在编写的库大量使用了元类。例如,这是一个基本的单例实现:

class SingletonMeta(type):
_instance = None

def __call__(self, *args, **kwargs):
if self._instance is None:
self._instance = super().__call__(*args, **kwargs)

return self._instance

class ExampleSingleton(metaclass=SingletonMeta):
pass

这工作得很好,但是当使用多重继承并且另一个类也有一个元类时就会出现问题。元类在标准库中相当普遍;最值得注意的是 abc.ABCMeta .制作抽象单例的天真尝试失败了:

class AbstractSingleton(ExampleSingleton, abc.ABC):
pass

Traceback (most recent call last):
File "untitled.py", line 25, in <module>
class AbstractSingleton(ExampleSingleton, abc.ABC):
TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases

解决方法很简单——创建一个继承自 SingletonMetaABCMeta 的新元类——但对于任何想使用我的库的人来说,这真的很烦人。

class AbstractSingletonMeta(SingletonMeta, abc.ABCMeta):
pass

class AbstractSingleton(metaclass=AbstractSingletonMeta):
pass

# no metaclass conflict

处理这个问题的最佳方法是什么?

我的一些想法:

  1. 由于抽象类相当普遍,我可以使 SingletonMeta 成为 ABCMeta 的子类。
  2. 为了方便用户,我可以在我的库中实现 AbstractSingletonMeta
  3. 因为任何可调用对象都可以用作元类,所以我可以实现一个自动合并所有父类的元类的函数。 (用法类似于 class AbstractSingleton(ExampleSingleton, abc.ABC, metaclass=auto_merge_metaclasses):)
  4. 本着“显式优于隐式”的精神,我无能为力,让用户解决元类冲突。

最佳答案

由于有关所需元类和需要组合的内容的所有信息已经存在于基类中,并且这些信息已传递给元类调用,因此可以有一个可调用对象来检查所有基类及其使用的元类,并动态创建一个组合元类。

types 模块有一些可调用项,否则可以很容易地为一组基类选择正确的元类。因此,如果您使用的所有元类都可以按任意顺序组合,那么下面的函数应该足以满足您的需求:

from types import prepare_class

def combine_meta(name, bases, namespace, **kwargs):
metaclasses = {prepare_class(name, (base,))[0] for base in bases}
metaclasses.discard(type)

if len(metaclasses) > 1:
meta_name = '_'.join(mcs.__name__ for mcs in metaclasses)
metaclass = combine_meta(meta_name, tuple(metaclasses), {})
elif len(metaclasses) == 1:
metaclass = metaclasses.pop()
else:
metaclass = type
return metaclass(name, bases, namespace, **kwargs)

我已经在交互式解释器中用这个序列对此进行了测试,并且到目前为止它有效:

class M1(type): pass
class M2(type): pass
class A(metaclass=M1): pass
class B(metaclass=M2): pass
class C(A, B): pass # This raises a metaclassconflict
class C(A, B, metaclass=combine_meta): pass

关于python - 在大量使用元类的库中,如何避免因元类冲突而烦扰用户?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51856491/

32 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com