(AttributeError: __enter__) when using __new__ magic method
(AttributeError: __enter__) when using __new__ magic method
我正在尝试使用 __new__
方法在处理之前检查参数有效性 (str),所以我正在执行以下操作:
class foo:
def __new__(cls, argument):
if not isinstance(argument, str):
raise TypeError('argument must be str')
print("passed __new__")
def __init__(self, argument):
self.argument = argument
print("passed __init__")
def __enter__(self):
print("passed __enter__")
def __exit__(self, *args):
print("passed __exit__")
然后,当我使用调用 __enter__
和 __exit__
的 with
关键字调用它时
with foo('test'):
print("i am between __enter__ and __exit__, damn!")
我得到这个输出:
passed __new__
AttributeError: __enter__
我期望这个输出:
passed __new__
passed __init__
passed __enter__
i am between __enter__ and __exit__, damn!
passed __exit__
我在完全删除 __new__
方法时注意到;它会起作用。为什么使用 __new__
会破坏它?以及如何在 __new__
现有的情况下让它工作?
__new__
必须实际创建 return 您的 class.
的一个实例
class foo:
def __new__(cls, argument):
if not isinstance(argument, str):
raise TypeError('argument must be str')
print("passed __new__")
<b>return super().__new__(cls)</b>
def __init__(self, argument):
self.argument = argument
print("passed __init__")
def __enter__(self):
print("passed __enter__")
def __exit__(self, *args):
print("passed __exit__")
在您的原始代码中,foo.__new__
returned None
,实际上 None
没有属性 __enter__
。此外,由于 None
不是 foo
的实例,因此抑制了对 foo.__init__
的隐式调用。
因为 foo
是 type
的实例,调用 foo('test')
是
的缩写
type.__call__(foo, 'test')
你可以想象 __call__
的定义类似于
def __call__(cls, *args, **kwargs):
obj = cls.__new__(*args, **kwargs)
if isinstance(obj, cls):
obj.__init__(*args, **kwargs)
return obj
覆盖 __new__
意味着您想要更改 创建实例的方式 ,而覆盖 __init__
意味着您想要更改已创建实例的方式得到初始化。在这种情况下,如果参数类型错误,您可以完全避免创建新实例。
我正在尝试使用 __new__
方法在处理之前检查参数有效性 (str),所以我正在执行以下操作:
class foo:
def __new__(cls, argument):
if not isinstance(argument, str):
raise TypeError('argument must be str')
print("passed __new__")
def __init__(self, argument):
self.argument = argument
print("passed __init__")
def __enter__(self):
print("passed __enter__")
def __exit__(self, *args):
print("passed __exit__")
然后,当我使用调用 __enter__
和 __exit__
的 with
关键字调用它时
with foo('test'):
print("i am between __enter__ and __exit__, damn!")
我得到这个输出:
passed __new__
AttributeError: __enter__
我期望这个输出:
passed __new__
passed __init__
passed __enter__
i am between __enter__ and __exit__, damn!
passed __exit__
我在完全删除 __new__
方法时注意到;它会起作用。为什么使用 __new__
会破坏它?以及如何在 __new__
现有的情况下让它工作?
__new__
必须实际创建 return 您的 class.
class foo:
def __new__(cls, argument):
if not isinstance(argument, str):
raise TypeError('argument must be str')
print("passed __new__")
<b>return super().__new__(cls)</b>
def __init__(self, argument):
self.argument = argument
print("passed __init__")
def __enter__(self):
print("passed __enter__")
def __exit__(self, *args):
print("passed __exit__")
在您的原始代码中,foo.__new__
returned None
,实际上 None
没有属性 __enter__
。此外,由于 None
不是 foo
的实例,因此抑制了对 foo.__init__
的隐式调用。
因为 foo
是 type
的实例,调用 foo('test')
是
type.__call__(foo, 'test')
你可以想象 __call__
的定义类似于
def __call__(cls, *args, **kwargs):
obj = cls.__new__(*args, **kwargs)
if isinstance(obj, cls):
obj.__init__(*args, **kwargs)
return obj
覆盖 __new__
意味着您想要更改 创建实例的方式 ,而覆盖 __init__
意味着您想要更改已创建实例的方式得到初始化。在这种情况下,如果参数类型错误,您可以完全避免创建新实例。