__new__ 方法给出错误 object.__new__() 只接受一个参数(要实例化的类型)
__new__ method giving error object.__new__() takes exactly one argument (the type to instantiate)
为什么下面的代码会报错?
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)
instance = super(Foo, cls).__new__(cls,*args, **kwargs)
是正确的。但是,you 负责首先删除您的 class 引入的参数,以便在最终调用 object.__new__
时,*args
和 [=13] =] 为空。
您的代码应该类似于
class Foo:
def __new__(cls, <b>a, b,</b> *args, **kwargs):
print("Creating Instance")
instance = super(Foo, cls).__new__(cls, *args, **kwargs)
return instance
def __init__(self, a, b, <b>*args, **kwargs</b>):
<b>super().__init__(*args, **kwargs)</b>
self.a = a
self.b = b
此定义会从 args
中删除您的新参数 a
和 b
,然后再将其传递给 MRO 的下一个人。 __init__
.
同样
object.__new__(cls)
,参数是cls
,不是(cls, *args, **kwargs)
object.__new__()
签名是(*args, **kwargs)
,你可以用inspect.signature
函数来查看。
但是为什么会出现这个错误呢? TLDR:因为您定义了自定义 __new__
方法。
小研究
所有测试均在 Python 3.9.1.
上完成
考虑下一步 class。
class MyClass:
def __init__(self): pass
让我们调用object.__new__()
:
>>> object.__new__(MyClass, *range(10), **{f'a{i}': i for i in range(10)})
<__main__.MyClass object at 0x000001E7B15B3550>
完全没有问题。
这个class只有自定义__init__
,没有自定义__new__
。
现在尝试为您的 Foo 执行相同的调用:
>>> object.__new__(Foo, *range(10), **{f'a{i}': i for i in range(10)})
Traceback (most recent call last):
File "<input>", line 1, in <module>
TypeError: object.__new__() takes exactly one argument (the type to instantiate)
关于 object.__new__()
的异常。
这个 class 有自定义的 __init__
和 __new__
。
当仅定义自定义 __new__
时,您将看到相同的错误:
>>> class OnlyNew:
... def __new__(cls, *args, **kwargs): return super().__new__(cls)
>>> object.__new__(OnlyNew, *range(10), **{f'a{i}': i for i in range(10)})
Traceback (most recent call last):
File "<input>", line 1, in <module>
TypeError: object.__new__() takes exactly one argument (the type to instantiate)
让我们检查一个没有自定义 __init__
和 __new__
的 class。
>>> class A: pass
>>> object.__new__(A, *range(10), **{f'a{i}': i for i in range(10)})
Traceback (most recent call last):
File "<input>", line 1, in <module>
TypeError: A() takes no arguments
完全不同的错误。
让我们看看它是如何与继承一起工作的。
从 A 派生并定义 __init__
.
>>> class B(A):
... def __init__(self): pass
>>> object.__new__(B, *range(10), **{f'a{i}': i for i in range(10)})
<__main__.B object at 0x000001E7B15D23A0>
派生自 MyClass,不定义任何内容。
>>> class MC(MyClass): pass
>>> object.__new__(MC, *range(10), **{f'a{i}': i for i in range(10)})
<__main__.MC object at 0x000001E7B15D2CA0>
派生自 MyClass 并定义 __new__
。
>>> class Sub(MyClass):
def __new__(cls, *args, **kwargs): return super().__new__(cls)
>>> object.__new__(Sub, *range(10), **{f'a{i}': i for i in range(10)})
Traceback (most recent call last):
File "<input>", line 1, in <module>
TypeError: object.__new__() takes exactly one argument (the type to instantiate)
从 Foo 派生并且不定义任何内容。
>>> class F(Foo): pass
>>> object.__new__(F, *range(10), **{f'a{i}': i for i in range(10)})
Traceback (most recent call last):
File "<input>", line 1, in <module>
TypeError: object.__new__() takes exactly one argument (the type to instantiate)
现在让我们来看一个绝对奇特的案例:
class Base:
def __init__(self): pass
def __new__(cls, *args, **kwargs): return super().__new__(cls)
class Sub(Base):
def __init__(self): pass
__new__ = object.__new__
class Free:
def __init__(self): pass
__new__ = object.__new__
>>> object.__new__(Free, *range(10), **{f'a{i}': i for i in range(10)})
<__main__.Free object at 0x000001E7B15C5A90>
>>> object.__new__(Sub, *range(10), **{f'a{i}': i for i in range(10)})
Traceback (most recent call last):
File "<input>", line 1, in <module>
TypeError: object.__new__() takes exactly one argument (the type to instantiate)
Sub 和 Free 都没有自定义 __new__
方法 - 在 class 中 __new__
是 object.__new__()
。
但是创建 Sub 会引发错误,而创建 Free 则不会。
似乎 object.__new__()
检查的不是 getattr(A_Class, '__new__', object.__new__) is object.__new__
,而是 all(getattr(cls, '__new__', object.__new__) is object.__new__ for cls in A_Class.mro())
.
结论
- 如果 class 在其 MRO 中具有自定义
__new__
,则使用 >1 个参数调用 object.__new__()
会引发 TypeError。
- 如果 class 在其 MRO 中只有自定义
__init__
而没有自定义 __new__
,则使用 >1 个参数调用 object.__new__()
会创建一个正确的实例。
- 如果 class 在其 MRO 中没有自定义
__init__
和 __new__
,则使用 >1 个参数调用 object.__new__()
会引发 TypeError。
这应该有效:
class Foo:
def __new__(cls, a, b):
print("Creating Instance")
instance = super(Foo, cls).__new__(cls)
return instance
def __init__(self, a, b):
self.a = a
self.b = b
foo_1 = Foo(a=1, b=2)
foo_2 = Foo(a=1, b=3)
如果您想使用单例设计模式,并在构造函数中使用参数创建 class 的实例,这应该可行:
class FooSingleton:
_instances = {}
def __new__(cls, a, b):
if cls not in cls._instances:
print('creating new FooSingleton instance')
cls._instances[cls] = super(FooSingleton, cls).__new__(cls)
else:
print('using FooSingleton instance')
return cls._instances[cls]
def __init__(self, a, b):
self.a = a
self.b = b
foo_s1 = FooSingleton(a=1, b=2)
foo_s2 = FooSingleton(a=1, b=3)
除了来自 Guido van Rossum 的 and answer, It's good to have this response。
这解决了 object.__new__
在子类中覆盖或不覆盖 __new__
时的行为,以及传递该方法的额外参数会发生什么。
There's no point in calling
object.__new__()
with more than a class parameter, and any code that
did so was just dumping those args into a black hole.
The only time when it makes sense for object.__new__()
to ignore extra
arguments is when it's not being overridden, but __init__
is being
overridden -- then you have a completely default __new__
and the
checking of constructor arguments is relegated to __init__
.
The purpose of all this is to catch the error in a call like
object(42) which (again) passes an argument that is not used. This is
often a symptom of a bug in your program.
from inspect import signature
print(signature(object.__new__))
print('------------------------------')
print(signature(object.__init__))
print('------------------------------')
object(42)
输出:
(*args, **kwargs)
------------------------------
(self, /, *args, **kwargs)
------------------------------
Traceback (most recent call last):
File "<>", line 7, in <module>
object(42)
TypeError: object() takes no arguments
您无需担心将参数传递给超类。这些参数也将传递到 __init__
调用中。
class User(object):
def __new__(cls, *args, **kwargs):
# do some logic with the initial parameters
return super().__new__(cls)
为什么下面的代码会报错?
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)
instance = super(Foo, cls).__new__(cls,*args, **kwargs)
是正确的。但是,you 负责首先删除您的 class 引入的参数,以便在最终调用 object.__new__
时,*args
和 [=13] =] 为空。
您的代码应该类似于
class Foo:
def __new__(cls, <b>a, b,</b> *args, **kwargs):
print("Creating Instance")
instance = super(Foo, cls).__new__(cls, *args, **kwargs)
return instance
def __init__(self, a, b, <b>*args, **kwargs</b>):
<b>super().__init__(*args, **kwargs)</b>
self.a = a
self.b = b
此定义会从 args
中删除您的新参数 a
和 b
,然后再将其传递给 MRO 的下一个人。 __init__
.
object.__new__(cls)
,参数是cls
,不是(cls, *args, **kwargs)
object.__new__()
签名是(*args, **kwargs)
,你可以用inspect.signature
函数来查看。
但是为什么会出现这个错误呢? TLDR:因为您定义了自定义 __new__
方法。
小研究
所有测试均在 Python 3.9.1.
上完成考虑下一步 class。
class MyClass:
def __init__(self): pass
让我们调用object.__new__()
:
>>> object.__new__(MyClass, *range(10), **{f'a{i}': i for i in range(10)})
<__main__.MyClass object at 0x000001E7B15B3550>
完全没有问题。
这个class只有自定义__init__
,没有自定义__new__
。
现在尝试为您的 Foo 执行相同的调用:
>>> object.__new__(Foo, *range(10), **{f'a{i}': i for i in range(10)})
Traceback (most recent call last):
File "<input>", line 1, in <module>
TypeError: object.__new__() takes exactly one argument (the type to instantiate)
关于 object.__new__()
的异常。
这个 class 有自定义的 __init__
和 __new__
。
当仅定义自定义 __new__
时,您将看到相同的错误:
>>> class OnlyNew:
... def __new__(cls, *args, **kwargs): return super().__new__(cls)
>>> object.__new__(OnlyNew, *range(10), **{f'a{i}': i for i in range(10)})
Traceback (most recent call last):
File "<input>", line 1, in <module>
TypeError: object.__new__() takes exactly one argument (the type to instantiate)
让我们检查一个没有自定义 __init__
和 __new__
的 class。
>>> class A: pass
>>> object.__new__(A, *range(10), **{f'a{i}': i for i in range(10)})
Traceback (most recent call last):
File "<input>", line 1, in <module>
TypeError: A() takes no arguments
完全不同的错误。
让我们看看它是如何与继承一起工作的。
从 A 派生并定义 __init__
.
>>> class B(A):
... def __init__(self): pass
>>> object.__new__(B, *range(10), **{f'a{i}': i for i in range(10)})
<__main__.B object at 0x000001E7B15D23A0>
派生自 MyClass,不定义任何内容。
>>> class MC(MyClass): pass
>>> object.__new__(MC, *range(10), **{f'a{i}': i for i in range(10)})
<__main__.MC object at 0x000001E7B15D2CA0>
派生自 MyClass 并定义 __new__
。
>>> class Sub(MyClass):
def __new__(cls, *args, **kwargs): return super().__new__(cls)
>>> object.__new__(Sub, *range(10), **{f'a{i}': i for i in range(10)})
Traceback (most recent call last):
File "<input>", line 1, in <module>
TypeError: object.__new__() takes exactly one argument (the type to instantiate)
从 Foo 派生并且不定义任何内容。
>>> class F(Foo): pass
>>> object.__new__(F, *range(10), **{f'a{i}': i for i in range(10)})
Traceback (most recent call last):
File "<input>", line 1, in <module>
TypeError: object.__new__() takes exactly one argument (the type to instantiate)
现在让我们来看一个绝对奇特的案例:
class Base:
def __init__(self): pass
def __new__(cls, *args, **kwargs): return super().__new__(cls)
class Sub(Base):
def __init__(self): pass
__new__ = object.__new__
class Free:
def __init__(self): pass
__new__ = object.__new__
>>> object.__new__(Free, *range(10), **{f'a{i}': i for i in range(10)})
<__main__.Free object at 0x000001E7B15C5A90>
>>> object.__new__(Sub, *range(10), **{f'a{i}': i for i in range(10)})
Traceback (most recent call last):
File "<input>", line 1, in <module>
TypeError: object.__new__() takes exactly one argument (the type to instantiate)
Sub 和 Free 都没有自定义 __new__
方法 - 在 class 中 __new__
是 object.__new__()
。
但是创建 Sub 会引发错误,而创建 Free 则不会。
似乎 object.__new__()
检查的不是 getattr(A_Class, '__new__', object.__new__) is object.__new__
,而是 all(getattr(cls, '__new__', object.__new__) is object.__new__ for cls in A_Class.mro())
.
结论
- 如果 class 在其 MRO 中具有自定义
__new__
,则使用 >1 个参数调用object.__new__()
会引发 TypeError。 - 如果 class 在其 MRO 中只有自定义
__init__
而没有自定义__new__
,则使用 >1 个参数调用object.__new__()
会创建一个正确的实例。 - 如果 class 在其 MRO 中没有自定义
__init__
和__new__
,则使用 >1 个参数调用object.__new__()
会引发 TypeError。
这应该有效:
class Foo:
def __new__(cls, a, b):
print("Creating Instance")
instance = super(Foo, cls).__new__(cls)
return instance
def __init__(self, a, b):
self.a = a
self.b = b
foo_1 = Foo(a=1, b=2)
foo_2 = Foo(a=1, b=3)
如果您想使用单例设计模式,并在构造函数中使用参数创建 class 的实例,这应该可行:
class FooSingleton:
_instances = {}
def __new__(cls, a, b):
if cls not in cls._instances:
print('creating new FooSingleton instance')
cls._instances[cls] = super(FooSingleton, cls).__new__(cls)
else:
print('using FooSingleton instance')
return cls._instances[cls]
def __init__(self, a, b):
self.a = a
self.b = b
foo_s1 = FooSingleton(a=1, b=2)
foo_s2 = FooSingleton(a=1, b=3)
除了来自 Guido van Rossum 的
这解决了 object.__new__
在子类中覆盖或不覆盖 __new__
时的行为,以及传递该方法的额外参数会发生什么。
There's no point in calling
object.__new__()
with more than a class parameter, and any code that did so was just dumping those args into a black hole.The only time when it makes sense for
object.__new__()
to ignore extra arguments is when it's not being overridden, but__init__
is being overridden -- then you have a completely default__new__
and the checking of constructor arguments is relegated to__init__
.The purpose of all this is to catch the error in a call like object(42) which (again) passes an argument that is not used. This is often a symptom of a bug in your program.
from inspect import signature
print(signature(object.__new__))
print('------------------------------')
print(signature(object.__init__))
print('------------------------------')
object(42)
输出:
(*args, **kwargs)
------------------------------
(self, /, *args, **kwargs)
------------------------------
Traceback (most recent call last):
File "<>", line 7, in <module>
object(42)
TypeError: object() takes no arguments
您无需担心将参数传递给超类。这些参数也将传递到 __init__
调用中。
class User(object):
def __new__(cls, *args, **kwargs):
# do some logic with the initial parameters
return super().__new__(cls)