为什么我的类没有被“def __int__”或“def _init_”初始化?为什么我会得到一个“不带参数”的 TypeError 或 AttributeError?

问题描述 投票:0回答:1

如果您的问题与此重复,那是因为您有一个代码示例,其中包含以下任一内容:

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__() should return None, not 'int' for the opposite problem - writing

__init__
instead of
__int__
when trying to make a class that can be converted to integer.

python class initialization typeerror magic-methods
1个回答
6
投票

这是因为代码有一个简单的印刷错误:该方法应该命名为

__init__
- 注意拼写,注意每边有两个下划线。

异常消息是什么意思,它们与问题有什么关系?

正如人们可能猜到的那样,

TypeError
是一个
Error
,它与某物的
Type
有关。在这种情况下,含义有点紧张:Python also 将此错误类型用于函数调用,其中参数(您在
()
之间放置的内容以调用函数、类构造函数或其他“可调用”)不能正确分配给参数(使用
()
语法编写函数时放在
def
之间的东西)。

在出现

TypeError
的示例中,
Example
的类构造函数不带参数。为什么? 因为它使用的是基础
object
构造函数
,它不带参数。这只是遵循正常的继承规则:没有在本地定义
__init__
,因此使用超类中的一个 - 在本例中为
object
-。

同样,

AttributeError
是一个
Error
,它与某物的
Attribute
相关。这非常简单:
Example
的实例没有任何
.attribute
属性,因为构造函数(由于拼写错误,再次来自
object
)没有设置一个。

为什么没有更早出现问题,例如,类定义本身?

因为名称输入错误的方法在语法上仍然有效。只有语法错误(报告为

SyntaxError
;是的,这是一个异常,是的,它在实际程序中有有效的用途)可以在代码运行之前被捕获。 Python 不会为名为
_init_
(每边一个下划线)的方法分配任何特殊含义,因此它不关心参数是什么。虽然
__int__
用于将类的实例转换为整数,并且除了
self
之外不应该有任何参数,它仍然是 syntactically valid.

您的 IDE 可能会警告您有关采用可疑参数的

__int__
方法(即除
self
之外的任何参数)。但是,a) 并不能完全解决问题(见下文),b) IDE 可能首先帮助您弄错了(通过提出错误的自动完成建议)。

_init_
错字现在似乎不那么常见了。我的猜测是人们过去常常在阅读排版不佳的书籍中的示例代码后这样做。

问题还可能如何表现?

在成功创建实例(但未正确初始化)的情况下,任何类型的问题都可能在以后发生(取决于为什么需要正确初始化)。例如:

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

如果您打算将类转换为整数并且还故意写了

__int__
,那么last将优先:

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)

(请注意,

__int__
not 隐式用于将类的实例转换为列表或元组的索引。这是由
__index__
完成的。)

我以后应该如何防范这个问题?

没有灵丹妙药。我发现如果班级需要的话,始终将

__init__
(和/或
__new__
)作为班级中的第一个方法的惯例会有所帮助。但是,校对或培训是无可替代的。

© www.soinside.com 2019 - 2024. All rights reserved.