【问题标题】: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_\" 初始化的?为什么我会得到一个“不带参数”类型错误或属性错误?
【发布时间】:2023-02-08 09:41:42
【问题描述】:

如果您的问题作为此问题的副本而被关闭,那是因为您有一个代码示例,其中包含以下任一内容:

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

或者,该类的实例似乎缺少属性:

>>> 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 程序员编写的代码中的两个最常见的印刷错误而创建。虽然由拼写错误引起的问题通常会因此而关闭,但在这种情况下有一些有用的东西需要解释,并且有一个重复的目标可以更快地关闭问题。我试图将问题设计为易于搜索。

【问题讨论】:

    标签: python class initialization typeerror magic-methods


    【解决方案1】:

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

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

    正如人们可能猜到的那样,TypeError 是与某物的 Type 有关的 Error。在这种情况下,意思有点紧张:Python将此错误类型用于函数调用,其中参数(您在 () 之间放置的内容,以便调用函数、类构造函数或其他“可调用”)无法正确分配给参数(您在 @987654326 之间放置的内容) @ 使用def 语法编写函数时)。

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

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

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

    因为名称输入错误的方法在语法上仍然有效。只有语法错误(报告为SyntaxError;是的,这是一个异常,是的,它在实际程序中有有效的用途)可以在代码运行之前被捕获。 Python 不会为名为@9​​87654340@(两边各有一个下划线)的方法赋予任何特殊含义,因此它不关心参数是什么。虽然 __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__)作为类中的第一个方法的约定(如果类需要的话)会有所帮助。但是,校对或培训是无可替代的。

    【讨论】:

      猜你喜欢
      • 2022-06-21
      • 1970-01-01
      • 2015-07-05
      • 2014-04-09
      • 2016-08-04
      • 1970-01-01
      • 1970-01-01
      • 2017-01-04
      • 1970-01-01
      相关资源
      最近更新 更多