__new__
должен фактически создать и вернуть экземпляр вашего класса.
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__
вернул 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__
означает, что вы хотите изменить способ создания экземпляра . 1027 *, а переопределение __init__
означает, что вы хотите изменить способ, которым уже созданный экземпляр получает инициализированный . В этом случае вы вообще не будете создавать новый экземпляр, если аргумент имеет неправильный тип.