Python 制作内置类的副本
我正在尝试编写一个函数,它从类创建类,而不修改原始类 简单解决方案(基于) 工作正常,除了类型本身:Python 制作内置类的副本,python,python-3.x,types,copy,cpython,Python,Python 3.x,Types,Copy,Cpython,我正在尝试编写一个函数,它从类创建类,而不修改原始类 简单解决方案(基于) 工作正常,除了类型本身: >>> class_operator(type) Traceback (most recent call last): File "<input>", line 1, in <module> TypeError: type __qualname__ must be a str, not getset_descriptor 结果对象的行为与原始类型不
>>> class_operator(type)
Traceback (most recent call last):
File "<input>", line 1, in <module>
TypeError: type __qualname__ must be a str, not getset_descriptor
结果对象的行为与原始类型不同
>>> type_copy = class_operator(type)
>>> type_copy is type
False
>>> type_copy('')
Traceback (most recent call last):
File "<input>", line 1, in <module>
TypeError: descriptor '__init__' for 'type' objects doesn't apply to 'type' object
>>> type_copy('empty', (), {})
Traceback (most recent call last):
File "<input>", line 1, in <module>
TypeError: descriptor '__init__' for 'type' objects doesn't apply to 'type' object
>>type\u copy=class\u运算符(type)
>>>类型\副本为类型
假的
>>>键入副本(“”)
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
TypeError:“类型”对象的描述符“\uuuuu init\uuuuuuuu”不适用于“类型”对象
>>>键入复制('empty',(),{})
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
TypeError:“类型”对象的描述符“\uuuuu init\uuuuuuuu”不适用于“类型”对象
为什么?
有人能解释一下Python内部防止复制
类型
类(以及许多其他内置类)的机制是什么吗?这里的问题是类型
在其\uuuuuu dict\uuuuu
中有一个\uuuuuuuuu qualname\uuuuuuuuuuuuu>的属性,而不是字符串:
>>> type.__qualname__
'type'
>>> vars(type)['__qualname__']
<attribute '__qualname__' of 'type' objects>
这就是为什么有必要从\uuuuu dict\uuuu
中删除\uuuu qualname\uuuu
至于您的type\u copy
不可调用的原因:这是因为type.\uu call\uu
拒绝任何不是type
子类的内容。这对于三参数形式都是正确的:
>>> type.__call__(type, 'x', (), {})
<class '__main__.x'>
>>> type.__call__(type_copy, 'x', (), {})
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: descriptor '__init__' for 'type' objects doesn't apply to 'type' object
这是不容易规避的。修复3参数形式非常简单:我们将副本设置为类型的空子类
>>> type_copy = type('type_copy', (type,), {})
>>> type_copy('MyClass', (), {})
<class '__main__.MyClass'>
>>> class TypeCopyMeta(type):
... def __call__(self, *args):
... if len(args) == 1:
... return type(*args)
... return super().__call__(*args)
...
>>> type_copy = TypeCopyMeta('type_copy', (type,), {})
>>> type_copy(3) # works
<class 'int'>
>>> type_copy('MyClass', (), {}) # also works
<class '__main__.MyClass'>
>>> type(type), type(type_copy) # but they're not identical
(<class 'type'>, <class '__main__.TypeCopyMeta'>)
类型
很难复制的原因有两个:
它是用C实现的。如果您试图复制其他内置类型,如int
或str
,您将遇到类似的问题
type
本身就是一个例子:
详细的解决方案是创建一个自定义元类:
import builtins
def copy_class(cls):
if cls is type:
namespace = {}
bases = (cls,)
class metaclass(type):
def __call__(self, *args):
if len(args) == 1:
return type(*args)
return super().__call__(*args)
metaclass.__name__ = type.__name__
metaclass.__qualname__ = type.__qualname__
# if it's a builtin class, copy it by subclassing
elif getattr(builtins, cls.__name__, None) is cls:
namespace = {}
bases = (cls,)
metaclass = type
else:
namespace = dict(vars(cls))
bases = cls.__bases__
metaclass = type
cls_copy = metaclass(cls.__name__, bases, namespace)
cls_copy.__qualname__ = cls.__qualname__
return cls_copy
谢谢,请检查更新部分的question@AzatIbrakov是的,我在忙着写答案的时候没有注意到更新。。。给我一秒钟它就要结束了,但是type\u copy(“”)
会给我们TypeError:type.\uu新的\uuuuuuuuuo()只接受3个参数(给定1个)
@AzatIbrakov更新。这在几乎所有内置类型上都会失败,不仅仅是type
。对于类型
,它会失败得特别厉害,但对于其他类型,它也不会正常工作。例如,如果您尝试以这种方式复制int
,则结果实例不支持算术、哈希或int
的任何功能。dict级别的复制无法深入到C中,无法复制需要复制的内容。我可以想象,有各种各样的极端情况阻止dict(vars(cls))
为复制类提供合适的基础。你需要一个类型的副本而不是子类化它的用例是什么;你只是把原件复制得很差。您是否希望类型\u copy is type
为真?除非class\u操作符
简单地返回type
本身,否则这种情况永远不会发生。@chepner:我正在等待type\u副本是type
为False
(我知道怎么做)
>>> type.__call__(type, 3)
<class 'int'>
>>> type.__call__(type_copy, 3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: type.__new__() takes exactly 3 arguments (1 given)
>>> type_copy = type('type_copy', (type,), {})
>>> type_copy('MyClass', (), {})
<class '__main__.MyClass'>
>>> class TypeCopyMeta(type):
... def __call__(self, *args):
... if len(args) == 1:
... return type(*args)
... return super().__call__(*args)
...
>>> type_copy = TypeCopyMeta('type_copy', (type,), {})
>>> type_copy(3) # works
<class 'int'>
>>> type_copy('MyClass', (), {}) # also works
<class '__main__.MyClass'>
>>> type(type), type(type_copy) # but they're not identical
(<class 'type'>, <class '__main__.TypeCopyMeta'>)
>>> type(type)
<class 'type'>
import builtins
def copy_class(cls):
# if it's a builtin class, copy it by subclassing
if getattr(builtins, cls.__name__, None) is cls:
namespace = {}
bases = (cls,)
else:
namespace = dict(vars(cls))
bases = cls.__bases__
cls_copy = type(cls.__name__, bases, namespace)
cls_copy.__qualname__ = cls.__qualname__
return cls_copy
import builtins
def copy_class(cls):
if cls is type:
namespace = {}
bases = (cls,)
class metaclass(type):
def __call__(self, *args):
if len(args) == 1:
return type(*args)
return super().__call__(*args)
metaclass.__name__ = type.__name__
metaclass.__qualname__ = type.__qualname__
# if it's a builtin class, copy it by subclassing
elif getattr(builtins, cls.__name__, None) is cls:
namespace = {}
bases = (cls,)
metaclass = type
else:
namespace = dict(vars(cls))
bases = cls.__bases__
metaclass = type
cls_copy = metaclass(cls.__name__, bases, namespace)
cls_copy.__qualname__ = cls.__qualname__
return cls_copy