【发布时间】:2018-08-15 20:53:28
【问题描述】:
根据this answer,可以复制一个类对象cls
cls_copy = type('cls_copy', cls.__bases__, dict(cls.__dict__))
这适用于大多数正常情况。当cls 的元类不是type 时,它不起作用。我最初的天真修复是做
cls_copy = type(cls)('cls_copy', cls.__bases__, dict(cls.__dict__))
但是,这根本没有意义。没有办法知道元类的作用,正如this answer 对相关问题指出的那样,它如何转换输入字典,它需要哪些额外的关键字等等。
type 的原始用法几乎足够好,但有几个小例外:
- 由最终未调用
type.__new__的元类创建的__dict__可能与通常的代理对象类型不同。 - 扩展副本的类将没有正确的元类,这可能会导致意外行为。
- 在原始元类中定义的任何属性或其他数据描述符将不再在类对象上可用。
我愿意忽略第 1 项。如果我找到其他项目的可行解决方案,我愿意记录下这是一个极端案例。如果可以更改副本的元类,则可以解决第 2 项和第 3 项。我尝试过(再次,天真地)
cls_copy = type('cls_copy', cls.__bases__, dict(cls.__dict__),
metaclass=type(cls))
正如预期的那样,这只是引发了TypeError:
TypeError: __init_subclass__() takes no keyword arguments
鉴于docs,这是有道理的:
像它的标识一样,对象的类型也是不可更改的。 1
但是,footnote 声明
在某些受控条件下,在某些情况下可以更改对象的类型。不过这通常不是一个好主意,因为如果处理不当会导致一些非常奇怪的行为。
在什么条件下可以更改对象的类型,特别是类的类型?这是其中一种情况吗?如果是,如何?
注意
我知道copy.deepcopy 和继承在这里是可行的选择。出于这个问题的目的,我希望忽略这些替代方案并坚持使用与type 相关的技术。
【问题讨论】:
-
type.__new__(type(cls), cls.__bases__, ...)可能会起作用。我是否错过了任何极端情况? -
@internet_user。没有我不满意的:) 非常感谢。你愿意把它写下来作为正式的点吗?
-
@internet_user。我半信半疑的回答是“不”,所以我错过了这么简单的事情真是太棒了。
-
糟糕,是的,我忘记了名称参数。