【问题标题】:Is it possible to properly copy a class using type是否可以使用类型正确复制一个类
【发布时间】: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 的原始用法几乎足够好,但有几个小例外:

  1. 由最终未调用 type.__new__ 的元类创建的 __dict__ 可能与通常的代理对象类型不同。
  2. 扩展副本的类将没有正确的元类,这可能会导致意外行为。
  3. 在原始元类中定义的任何属性或其他数据描述符将不再在类对象上可用。

我愿意忽略第 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。我半信半疑的回答是“不”,所以我错过了这么简单的事情真是太棒了。
  • 糟糕,是的,我忘记了名称参数。

标签: python types metaclass


【解决方案1】:

您可以使用type.__new__(type(cls), cls.__name__, cls.__bases__, dict(cls.__dict__))。这使用了正常的type 创建过程,但创建了一个type(cls) 的实例而不是type

至于__metaclass__的问题,我想是因为__metaclass__通常是被调用的,所以type不能用。

【讨论】:

  • 在 :) 中添加名称
  • 文档说“在类定义中指定的任何 other 关键字参数都将传递给下面描述的所有元类操作。” [强调我的]。这意味着 metaclass 关键字不会出现在解释器之外。
  • 部分问题是我写了__metaclass__而不是metaclass,但无论哪种方式错误都是一样的。
  • 我希望你不介意我在dict(cls.__dict__) 中明确添加。如果没有dict,它会引发错误TypeError: type.__new__() argument 3 must be dict, not mappingproxy,所以我认为这值得一提。
  • 是的,没关系。
猜你喜欢
  • 2012-05-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多