【问题标题】: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 __init__”或“def __init__”方法不被用来初始化类?为什么我会收到“不接受任何参数”类型错误?
【发布时间】:2022-06-21 07:08:53
【问题描述】:

这是一个人工规范副本,专门用于防止新 Python 程序员编写的代码中两个最常见的印刷错误。虽然由拼写错误引起的问题通常会因此而关闭,但在这种情况下有一些有用的东西需要解释,并且有一个重复的目标可以更快地关闭问题。我尝试将问题设计为易于搜索。

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

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

这是因为代码有一个简单的拼写错误:该方法应该命名为__init__ - 注意拼写,注意上面有两个下划线每一边。

您可能还想知道:异常消息是什么意思,它与问题有何关系?为什么没有更早出现问题,例如,类定义本身?问题还可能如何表现?以后如何防范这个问题?

【问题讨论】:

  • 我投票结束这个问题,因为它不是为了征求更多答案,而只是为了提供有关常见错字的权威信息,以便金徽章持有者可以快速结束问题并提供参考在适当的情况下。
  • 出于同样的原因,我投票结束这个问题。

标签: python class initialization typeerror magic-methods


【解决方案1】:

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

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

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

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

因为名称输入错误的方法在语法上仍然有效。在代码运行之前,只能捕获语法错误(报告为SyntaxError;是的,这是一个异常,是的,它在实际程序中有有效的用途)。 Python 没有为名为 _init_ 的方法赋予任何特殊含义(每边有一个下划线),因此它不关心参数是什么。虽然__int__ 用于将类的实例转换为整数,并且除了self 之外不应有任何参数,但它仍然在语法上有效。

您的 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__,则最后一个将优先:

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__隐式用于将类的实例转换为列表或元组的索引。这是由 __index__ 完成的。)

以后如何防范这个问题?

没有灵丹妙药。如果班级需要,我发现始终将__init__(和/或__new__)作为班级中的第一个方法的约定会有所帮助。但是,校对或培训是无可替代的。

【讨论】:

    猜你喜欢
    • 2023-02-08
    • 2019-04-18
    • 2021-05-27
    • 1970-01-01
    • 2021-03-04
    • 1970-01-01
    • 1970-01-01
    • 2017-01-04
    • 1970-01-01
    相关资源
    最近更新 更多