Python __给出错误对象的新方法。uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu

Python __给出错误对象的新方法。uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu,python,python-3.x,magic-methods,Python,Python 3.x,Magic Methods,为什么下面的代码给出错误 class Foo: def __new__(cls, *args, **kwargs): print("Creating Instance") instance = super(Foo, cls).__new__(cls,*args, **kwargs) return instance def __init__(self, a, b): self.a = a self.b

为什么下面的代码给出错误

class Foo:
    def __new__(cls, *args, **kwargs):
        print("Creating Instance")
        instance = super(Foo, cls).__new__(cls,*args, **kwargs)
        return instance

    def __init__(self, a, b):
        self.a = a
        self.b = b

z= Foo(2,3)
它给出了以下错误

TypeError: object.__new__() takes exactly one argument (the type to instantiate)
这是正确的。但是,您需要首先删除类引入的参数,这样当最终调用
对象时,
*args
**kwargs
都是空的

您的代码应该类似于

class Foo:
    def __new__(cls, a, b, *args, **kwargs):
        print("Creating Instance")
        instance = super(Foo, cls).__new__(cls, *args, **kwargs)
        return instance

    def __init__(self, a, b, *args, **kwargs):
            super().__init__(*args, **kwargs)
            self.a = a
            self.b = b
Foo类:
定义新(cls、a、b、*ARG、**kwargs):
打印(“创建实例”)
实例=super(Foo,cls)。\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
返回实例
定义初始值(self、a、b、*args、**kwargs):
super()
self.a=a
self.b=b
此定义从
args
中删除新参数
a
b
,然后将其传递给MRO上的下一位。同样地,对于
\uuuuu init\uuuuuuuuuuuuuuuuuu

对象,参数是
cls
,而不是
(cls,*args,**kwargs)

对象。
签名是
(*args,**kwargs)
,您可以使用
inspect.signature函数对此进行检查

但是为什么你会有这个错误呢TLDR:因为您定义了自定义的
\uuuuu新方法

小型研究 所有测试都是在Python3.9.1上完成的

考虑下一节课

class-MyClass:
定义初始化(自我):通过
让我们调用
对象。\uuuu new\uuuu()

>>>对象.uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
没问题。这个类只有自定义的
\uuuuuu init\uuuuu
,没有自定义的
\uuuuuu new\uuuuuu

现在尝试对您的Foo执行相同的调用:

>>>object.\uuuuuuuuuuuuuuuuo(Foo,*range(10),**{f'a{i}):范围(10)中的i代表i)
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
TypeError:object.\uuuuuu new\uuuuuuuu()只接受一个参数(要实例化的类型)
有关
对象的异常。\uuuu new\uuuuu()
。这个类既有自定义的
\uuuuu init\uuuuu
又有
\uuuu new\uuuuu

当仅定义了自定义
\uuuuuuuuuuuuuuuuuuu
时,您将看到相同的错误:

>>仅类新建:
...     def(cls,*args,**kwargs):返回super()。(cls)
>>>对象.uuuuuuuuuuuuuuuu(OnlyNew,*范围(10),**{f'a{i}):范围(10)中的i代表i)
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
TypeError:object.\uuuuuu new\uuuuuuuu()只接受一个参数(要实例化的类型)
让我们检查一个没有自定义
\uuuuu init\uuuu
\uuuu new\uuuu
的类

>A类:合格
>>>对象。uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
TypeError:A()不接受任何参数
完全不同的错误

让我们看看它是如何与继承一起工作的。 从A派生并定义
\uuuuu init\uuuu

>>B类(A):
...     定义初始化(自我):通过
>>>对象.uuuuuuuuuuuuuuub,*范围(10),**{f'a{i}:i代表范围(10)中的i)
从MyClass派生,不定义任何内容

>>MC类(MyClass):通过
>>>对象。uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
从MyClass派生并定义
\uuuuuu new\uuuuu

>>类子类(MyClass):
def(cls,*args,**kwargs):返回super()。(cls)
>>>对象.uuuuuuuuuuuuuuuuuuuuuu(Sub,*范围(10),**{f'a{i}):范围(10)中的i代表i)
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
TypeError:object.\uuuuuu new\uuuuuuuu()只接受一个参数(要实例化的类型)
从Foo派生,不定义任何内容

>F类(Foo):通过
>>>对象.uuuuuuuuuuuuuuuuuuuf,*范围(10),**{F'a{i}:i代表范围(10)中的i)
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
TypeError:object.\uuuuuu new\uuuuuuuu()只接受一个参数(要实例化的类型)
现在让我们来看一个非常奇特的案例:

类库:
定义初始化(自我):通过
def(cls,*args,**kwargs):返回super()。(cls)
小类(基本类):
定义初始化(自我):通过
__新建=对象__
免费上课:
定义初始化(自我):通过
__新建=对象__
>>>object.\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
>>>对象.uuuuuuuuuuuuuuuuuuuuuu(Sub,*范围(10),**{f'a{i}):范围(10)中的i代表i)
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
TypeError:object.\uuuuuu new\uuuuuuuu()只接受一个参数(要实例化的类型)
Sub和Free都没有自定义的
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
方法-在这两个类中
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu。但是创建Sub会引发错误,而创建Free则不会。似乎是
object.\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu

结论
  • 如果类的属性中有
    \uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
    ,则使用>1个参数调用
    对象会引发TypeError
  • 如果一个类在其MRO中只有自定义的
    \uuuuu init\uuuuuuu
    ,而没有自定义的
    \uuuuuuuu新的
    ,则调用
    对象。
    和>1个参数将创建一个合适的实例
  • 如果类的MRO中既没有自定义的
    \uuuuuu init\uuuuu
    又没有自定义的
    \uuuuuu new\uuuuuu
    ,则调用
    对象。
    带有>1个参数会引发TypeError

  • 是什么让您认为这不应该产生错误?这是一个很好的建议,但我仍然无法理解为什么如果不重写new,那么一切都可以正常工作:new应该得到cls和构造函数参数。如果new没有被覆盖,那么它就是object?它会得到所有这些额外的参数(是吗?),并且从不抱怨,无论显式调用super()。\uuuuunew\uuuuuuuuuuu失败。此外,删除“引入的参数”并不总是可能的。例如,B类
    class Foo:
        def __new__(cls, a, b, *args, **kwargs):
            print("Creating Instance")
            instance = super(Foo, cls).__new__(cls, *args, **kwargs)
            return instance
    
        def __init__(self, a, b, *args, **kwargs):
                super().__init__(*args, **kwargs)
                self.a = a
                self.b = b