python - 在python中创建一个类实例,其基类由参数动态指定
问题描述
我需要做这样的事情:
class Base1:
def __init__(self, uniform_params):
pass
class Base2:
def __init__(self, uniform_params):
pass
class DynamicDerive(self, dynamicspec, uniform_params):
kls = dynamicspec.kls
kls.__init__self, uniform_params)
spec = SomeSpecificationObject()
spec.kls = Base1
x = DynamicDerive(spec, uniform_params)
spec2 = SomeSpecificationObject()
spec2.kls = Base2
y = DynamicDerive(spec2, some_more_uniform_params)
Base1 和 Base2 的参数一致且一致。要求是在创建实例时传入 DynamicDerive 要从中派生的类。
替代方案是“简单的”:创建 DynamicDerive1(Base1)、DynamicDerive2(Base2),但不幸的是:
- DynamicDerive 类在数百个地方使用。
- 在这里,无法预测未来用户会传入什么。用户可以创建 Base3、Base4 等。
因此,创建数百个相同类的整个片段的剪切/粘贴选项只是更改基类的名称,这不是一种选择。
假设这可以通过“重定向”API来解决,其中一个特殊的类会这样做:
class Base:
def __init__(self, redirectorkls, uniform_args):
self.redir = redirectorkls(uniformargs)
def fn1(self, *args, **kwargs):
return self.redir.fn1(*args, **kwargs)
def fn2(self, *args, **kwargs):
return self.redir.fn2(*args, **kwargs)
...
...
然而,虽然它会起作用,但这完全违背了练习的目的。必须有一种涉及元编程(元类)的方法来做到这一点。
不幸的是,查找元类编程教程都显示了如何从构造函数外部创建类,而上面需要的是在构造函数内部创建元类。
有人有任何线索吗?
[更新] - 然后我需要能够进一步从 DynamicDerive派生。GreenCloakGuy 通过提供一个可以完成任务的函数来很好地回答,但是不可能从函数派生类。
class DerivedFromDynamicDerive(DynamicDerive):
def __init__(self, dynamicspec, nonuniformparams, uniform_params):
self.nonuniformparams = nonuniformparams
DynamicDerive.__init__(self, dynamicspec, uniform_params)
(注意:因为这是实际的自由代码,所以需要的地方在这里: https ://git.libre-riscv.org/?p=ieee754fpu.git;a=blob;f=src/ieee754/fpadd/ addstages.py;h=2bc23df0dabf89f8a4e194d5e573a88d5d740d0e;hb=78cbe8c5131a84426a3cad4b0b3ed4ab7da49844#l19
SimpleHandShake 需要在大约 40 个位置进行动态替换,此 IEEE754 兼容 RTL 的用户可以指定他们希望使用的类。这只是需要此功能的 50 多个类中的一个)。
解决方案
如果您可以只使用多重继承,并且将参数配置为 Mixin 类,那么这件事会更干净——以至于在创建类时不需要特殊的元类或操作。
而且,当然,如果一个人既不需要issubclass
检查也不需要 的子类DynamicDerive
,一个工厂函数,它将接受基础,将注册表保留为缓存,并且只实例化新对象也不需要任何特殊的代码。
但是,如果您需要 MRO 中的参数基础比“DerivedClass”更高,正如您所要求的,那么在类实例化时自定义实例类的__call__
方法是覆盖元类的方法。(这是 Python 运行的,type.__call__
最终将调用类__new__
和__init__
方法)。
这件事在这里为我尝试过 - 看看它是否适合你:
import threading
class M(type):
registry = {}
recursing = threading.local()
recursing.check = False
mlock = threading.Lock()
def __call__(cls, *args, **kw):
mcls = cls.__class__
if mcls.recursing.check:
return super().__call__(*args, **kw)
spec = args[0]
base = spec.kls
if (cls, base) not in mcls.registry:
mcls.registry[cls, base] = type(
cls.__name__,
(cls, base) + cls.__bases__[1:],
{}
)
real_cls = mcls.registry[cls, base]
with mcls.mlock:
mcls.recursing.check = True
instance = real_cls.__class__.__call__(real_cls, *args, **kw)
mcls.recursing.check = False
return instance
我导入了这个,并在 Python 会话中运行这个片段:
In [54]: class DynamicDerive(metaclass=M):
...: def __init__(self, spec):
...: super().__init__(spec)
...:
...:
...: class Base1:
...: def __init__(self, uniform_params):
...: print("at base 1")
...:
...: class Base2:
...: def __init__(self, uniform_params):
...: print("at base 2")
...:
...:
...: SomeSpec = type("SomeSpec", (), {})
...:
...: spec1 = SomeSpec()
...: spec1.kls = Base1
...:
...: spec2 = SomeSpec()
...: spec2.kls = Base2
...:
...: a1 = DynamicDerive(spec1)
...: a2 = DynamicDerive(spec2)
at base 1
at base 2
In [55]: isinstance(a1, DynamicDerive)
Out[55]: True
In [56]: isinstance(a2, DynamicDerive)
Out[56]: True
In [57]: class D2(DynamicDerive): pass
In [58]: b1 = D2(spec1)
at base 1
In [59]: b1.__class__.__mro__
Out[59]: (__main__.D2, __main__.D2, __main__.DynamicDerive, __main__.Base1, object)
推荐阅读
- firebase - Flutter Streambuilder 是在 setState 上使用缓存还是再次从 firestore 数据库中检索所有文档?
- c# - 网络打印机忽略以编程方式发送的副本数量
- multithreading - Cocos2d-x Multithreading sceanrio 导致游戏崩溃
- swift - 在 SwiftUI 中将选取器更改为文本字段
- html - select2 动态更改选择选项图标
- regex - 正则表达式 - 捕获子文件夹的剩余页面
- docker - Docker 容器内的 SSH 密钥在被 GitLab CI 管道拉取时丢失
- laravel - 当多个请求传入服务器时,laravel 队列可以确保数据完整性吗?
- python - 在 mongoengine 中更新密码后,bcrypt(python)中的盐无效
- c# - Flutter - HttpClient 适用于应用程序,但不适用于浏览器。.NET Core 3.1 WebAPI + Flutter2