¿Por qué mi clase no se inicializa con "def __int__" o "def _init_"? ¿Por qué recibo un error de tipo "no acepta argumentos" o un error de atributo?
Si su pregunta se cerró como un duplicado de esto, es porque tenía un ejemplo de código que incluía algo como:
class Example:
def __int__(self, parameter):
self.attribute = parameter
o:
class Example:
def _init_(self, parameter):
self.attribute = parameter
Cuando posteriormente intenta crear una instancia de la clase, se produce un error:
>>> Example("an argument")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: Example() takes no arguments
(En algunas versiones de Python, el error puede decir TypeError: object.__new__() takes no parameters
.)
Alternativamente, a las instancias de la clase parece que les faltan atributos:
>>> 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'
Quizás también se pregunte: ¿qué significan estos mensajes de excepción y cómo se relacionan con el problema? ¿Por qué no ocurrió ningún problema antes, por ejemplo, con la definición de clase misma? ¿De qué otra manera podría manifestarse el problema? ¿Cómo puedo protegerme contra este problema en el futuro?
Esta es una pregunta canónica artificial creada específicamente para evitar dos de los errores tipográficos más comunes en el código escrito por nuevos programadores de Python. Si bien las preguntas causadas por un error tipográfico normalmente se cierran por ese motivo, hay algunas cosas útiles que explicar en este caso, y tener un objetivo duplicado permite cerrar las preguntas más rápido. He intentado diseñar la pregunta para que sea fácil de buscar.
Consulte también TypeError: __init__() debería devolver Ninguno, no 'int' para el problema opuesto: escribir __init__
en lugar de __int__
intentar crear una clase que se pueda convertir a un número entero.
Esto se debe a que el código tiene un error tipográfico simple : en su lugar, el método debería tener un nombre __init__
; tenga en cuenta la ortografía y tenga en cuenta que hay dos guiones bajos en cada lado.
¿Qué significan los mensajes de excepción y cómo se relacionan con el problema?
Como se podría adivinar, a TypeError
es un error que tiene que ver con el tipo de algo. En este caso, el significado es un poco forzado: Python también usa este tipo de error para llamadas a funciones donde los argumentos (las cosas que pones en el medio ()
para llamar a una función, constructor de clase u otro invocable ) no se pueden asignar correctamente a los parámetros. (las cosas que pones ()
al escribir una función usando la def
sintaxis).
En los ejemplos donde TypeError
ocurre a, el constructor de clase for Example
no acepta argumentos. ¿Por qué? Porque utiliza el object
constructor base , que no acepta argumentos. Eso es simplemente seguir las reglas normales de herencia: no hay ningún definido localmente, por lo que se usa __init__
el de la superclase, en este caso .object
De manera similar, an AttributeError
es un error que tiene que ver con un atributo de algo. Esto es bastante sencillo: la instancia de Example
no tiene ningún .attribute
atributo, porque el constructor (que, nuevamente, proviene object
debido al error tipográfico) no estableció ninguno.
¿Por qué no ocurrió ningún problema antes, por ejemplo, con la definición de clase misma?
Porque el método con un nombre escrito incorrectamente sigue siendo sintácticamente válido. SyntaxError
Solo se pueden detectar errores de sintaxis (reportados como ) antes de que se ejecute el código. Python no asigna ningún significado especial a los métodos nombrados _init_
(con un guión bajo a cada lado), por lo que no le importa cuáles sean los parámetros. Si bien __int__
se usa para convertir instancias de la clase a enteros y no debería tener ningún parámetro además self
, sigue siendo sintácticamente válido.
Es posible que su IDE pueda advertirle sobre un __int__
método que toma parámetros sospechosos (es decir, cualquier cosa además de self
). Sin embargo, a) eso no resuelve completamente el problema (ver más abajo), y b) el IDE podría haberlo ayudado a hacerlo mal en primer lugar (al hacer una mala sugerencia de autocompletar).
El _init_
error tipográfico parece ser mucho menos común hoy en día. Supongo que la gente solía hacer esto después de leer códigos de ejemplo de libros con una composición tipográfica deficiente.
¿De qué otra manera podría manifestarse el problema?
En el caso de que una instancia se cree correctamente (pero no se inicialice correctamente), cualquier tipo de problema podría ocurrir más adelante (dependiendo de por qué se necesitaba una inicialización adecuada). Por ejemplo:
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
Si tiene la intención de que la clase sea convertible a un número entero y también escribió __int__
deliberadamente, la última tendrá prioridad:
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)
¿Cómo podría protegerme contra el problema en el futuro?
No existe una fórmula mágica. Creo que ayuda un poco tener la convención de poner siempre __init__
(y/o __new__
) como el primer método en una clase, si la clase lo necesita. Sin embargo, nada sustituye a la revisión ni a la formación.