Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/361.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 制作内置类的副本_Python_Python 3.x_Types_Copy_Cpython - Fatal编程技术网

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