我正在开发的库中有许多原子类(Components/Mixins,不太确定如何调用它们),它们将被应用程序子类化。创建这种原子性是为了让应用程序只能使用它们需要的特性,并通过多重继承组合组件。
但是,有时无法确保这种原子性,因为某些组件可能依赖于另一个组件。例如,假设我有一个组件可以为对象提供图形表示,另一个组件使用该图形表示来执行一些碰撞检查。第一个是纯原子的,但是后者要求当前对象已经子类化了这个图形表示组件,这样它的方法就可以使用了。这是一个问题,因为我们必须以某种方式告诉这个库的用户,为了使用某个组件,他们还必须继承另一个组件。我们可以使这个碰撞组件成为视觉组件的子类,但是如果用户也将这个视觉组件子类化,它就不会工作,因为类不在同一级别(不像简单的菱形关系,这是需要的),并且会给出程序员难以理解的神秘元类错误。
因此,我想知道是否有任何很酷的方法,通过元类重定义或使用类装饰器,来标记这些非原子组件,当它们被子类化时,额外的依赖将被注入(inject)到当前对象中,如果它尚不可用。示例:
class AtomicComponent(object):
pass
@depends(AtomicComponent) # <- something like this?
class UnAtomicComponent(object):
pass
class UserClass(UnAtomicComponent): #automatically includes AtomicComponent
pass
class UserClass2(AtomicComponent, UnAtomicComponent): #also works without problem
pass
有人可以提示我该怎么做吗?或者如果有可能...
编辑: 由于元类解决方案是最好的解决方案是值得商榷的,因此我将在 2 天内不接受它。
其他解决方案可能是改进错误消息,例如,执行类似 UserClass2 的操作会给出一个错误,指出 UnAtomicComponent 已经扩展了该组件。然而,这会产生一个问题,即不可能使用两个 UnAtomicComponents,因为它们会在不同级别上子类化对象。
最佳答案
“元类”
这就是他们的目的!在创建类时,类参数贯穿于 元类代码,例如,您可以在其中检查基础并进行更改。
这运行没有错误——尽管它没有保留所需类的顺序 标有“depends”装饰器:
class AutoSubclass(type):
def __new__(metacls, name, bases, dct):
new_bases = set()
for base in bases:
if hasattr(base, "_depends"):
for dependence in base._depends:
if not dependence in bases:
new_bases.add(dependence)
bases = bases + tuple(new_bases)
return type.__new__(metacls, name, bases, dct)
__metaclass__ = AutoSubclass
def depends(*args):
def decorator(cls):
cls._depends = args
return cls
return decorator
class AtomicComponent:
pass
@depends(AtomicComponent) # <- something like this?
class UnAtomicComponent:
pass
class UserClass(UnAtomicComponent): #automatically includes AtomicComponent
pass
class UserClass2(AtomicComponent, UnAtomicComponent): #also works without problem
pass
(我从“object”中删除了继承,因为我声明了一个全局 __metaclass__
变量。所有类仍然是新样式类并具有这个元类。从对象或另一个类继承确实覆盖了全局__metaclass__
变量,类级别__metclass__
必须声明)
-- 编辑--
在没有元类的情况下,要走的路是让您的类正确地继承它们的依赖项。 Tehy 将不再是那个“原子”,但是,由于它们不能作为那个原子工作,所以可能无关紧要。
在下面的示例中,类 C 和 D 将是您的用户类:
>>> class A(object): pass
...
>>> class B(A, object): pass
...
>>>
>>> class C(B): pass
...
>>> class D(B,A): pass
...
>>>
关于python - Python 中的动态子类化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8944320/