Вопрос-Ответ

Why isn't my class initialized by "def __int__" or "def _init_"? Why do I get a "takes no arguments" TypeError, or an AttributeError?

Почему мой класс не инициализируется "def __int__" или "def _init_"? Почему я получаю ошибку типа "не принимает аргументов" или ошибку атрибута?

Если ваш вопрос был закрыт как дубликат этого, это потому, что у вас был образец кода, включающий что-то вроде:

class Example:
def __int__(self, parameter):
self.attribute = parameter

или:

class Example:
def _init_(self, parameter):
self.attribute = parameter

При последующей попытке создать экземпляр класса возникает ошибка:

>>> Example("an argument")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: Example() takes no arguments

(В некоторых версиях Python ошибка может вместо этого указывать TypeError: object.__new__() takes no parameters.)

С другой стороны, экземплярам класса, похоже, не хватает атрибутов:

>>> class Example:
... def __int__(self): # or _init_
... self.attribute = 'value'

>>> Example().attribute
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Example' object has no attribute 'attribute'

Вы также можете задаться вопросом: что означают эти сообщения об исключениях и как они связаны с проблемой? Почему проблема не возникла раньше, например, с самим определением класса? Как еще может проявляться проблема? Как я могу защититься от этой проблемы в будущем?


Это искусственный канонический вопрос, созданный специально для предотвращения двух наиболее распространенных опечаток в коде, написанном начинающими программистами на Python. Хотя вопросы, вызванные опечаткой, обычно закрываются по этой причине, в этом случае есть несколько полезных вещей, которые нужно объяснить, а наличие дублирующего целевого объекта позволяет быстрее закрывать вопросы. Я постарался сформулировать вопрос так, чтобы его было легко найти.

Смотрите также TypeError: __init__() должен возвращать None, а не 'int' для противоположной проблемы - записи __init__ вместо __int__ при попытке создать класс, который можно преобразовать в integer .

Переведено автоматически
Ответ 1

Это потому, что в коде допущена простая опечатка: вместо этого методу должно быть присвоено имя __init__ - обратите внимание на орфографию и на то, что с каждой стороны есть два подчеркивания.

Что означают сообщения об исключениях и как они связаны с проблемой?

Как можно догадаться, a TypeError - это ошибка, связанная с типом чего-либо. В этом случае смысл немного натянутый: Python также использует этот тип ошибки для вызовов функций, где аргументы (то, что вы помещаете между ними () для вызова функции, конструктора класса или другого вызываемого объекта) не могут быть должным образом присвоены параметрам (то, что вы помещаете между ними () при написании функции с использованием def синтаксиса).

В примерах, где встречается TypeError, конструктор класса для Example не принимает аргументы. Почему? Потому что он использует базовый object конструктор, который не принимает аргументы. Это просто соответствует обычным правилам наследования: нет __init__ определенного локально, поэтому используется класс из суперкласса - в данном случае, object.

Аналогично, AttributeError это ошибка, которая связана с атрибутом чего-либо. Это довольно просто: экземпляр Example не имеет никакого .attribute атрибута, потому что конструктор (который, опять же, происходит от object из-за опечатки) не установил его.

Почему раньше не возникало проблем, например, с самим определением класса?

Потому что метод с неправильно введенным именем по-прежнему синтаксически корректен. Перед запуском кода могут быть обнаружены только синтаксические ошибки (сообщаемые как SyntaxError). Python не присваивает никакого особого значения методам с именами _init_ (с одним подчеркиванием с каждой стороны), поэтому ему все равно, каковы параметры. Хотя __int__ используется для преобразования экземпляров класса в integer и не должен иметь никаких параметров, кроме self, он по-прежнему синтаксически допустим.

Ваша IDE может быть способна предупредить вас о __int__ методе, который принимает подозрительные параметры (т. Е. Что угодно, кроме self). Однако, а) это не полностью решает проблему (см. Ниже), и б) IDE, возможно, помогла вам ошибиться в первую очередь (сделав неправильное предложение автозаполнения).

_init_ Опечатка, кажется, в наши дни встречается гораздо реже. Я предполагаю, что люди делали это после прочтения примеров кода из книг с плохим набором текста.

Как еще может проявиться проблема?

В случае, когда экземпляр успешно создан (но не инициализирован должным образом), любая проблема потенциально может возникнуть позже (в зависимости от того, почему была необходима правильная инициализация). Например:

BOMB_IS_SET = True

class DefusalExpert():
def __int__(self):
global BOMB_IS_SET
BOMB_IS_SET = False
def congratulate(self):
if BOMB_IS_SET:
raise RuntimeError("everything blew up, gg")
else:
print("hooray!")

>>> d = DefusalExpert()
>>> d.congratulate()
Traceback (most recent call last):
...
RuntimeError: everything blew up, gg

Если вы хотите, чтобы класс был преобразован в integer, а также написали __int__ намеренно, то последний будет иметь приоритет:

class LoneliestNumber:
def __int__(self):
return 1
def __int__(self): # was supposed to be __init__
self.two = "can be as bad"

>>> int(LoneliestNumber())
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: __int__ returned non-int (type NoneType)

Как я могу защититься от этой проблемы в будущем?

Волшебной палочки не существует. Я считаю, что немного помогает правило всегда ставить __init__ (и / или __new__) в качестве первого метода в классе, если класс в нем нуждается. Однако нет замены для корректуры или обучения.

2023-12-17 10:50 python class