我收到类型错误。我如何解决它?

Kar*_*tel 11 python debugging typeerror

我经常从我的 Python 代码中得到未捕获的异常(错误),这些异常被描述为TypeErrors. 经过大量的实验和研究,我收集了以下示例(以及细微的变化):

TypeError: func() takes 0 positional arguments but 1 was given
TypeError: func() takes from 1 to 2 positional arguments but 3 were given
TypeError: func() got an unexpected keyword argument 'arg'
TypeError: func() missing 1 required positional argument: 'arg'
TypeError: func() missing 1 required keyword-only argument: 'arg'
TypeError: func() got multiple values for argument 'arg'
TypeError: MyClass() takes no arguments
TypeError: unsupported operand type(s) for +: 'int' and 'str'
TypeError: can only concatenate str (not "int") to str
TypeError: '>' not supported between instances of 'int' and 'str'
TypeError: can't multiply sequence by non-int of type 'float'
TypeError: string indices must be integers
TypeError: %d format: a number is required, not str
TypeError: not all arguments converted during string formatting
TypeError: list indices must be integers or slices, not str
TypeError: int() argument must be a string, a bytes-like object or a number, not 'list'
TypeError: a bytes-like object is required, not 'str'
TypeError: bad operand type for abs(): 'str'
TypeError: descriptor 'to_bytes' for 'int' objects doesn't apply to a 'str' object
TypeError: 'int' object is not iterable
TypeError: cannot unpack non-iterable int object
TypeError: 'int' object is not callable
TypeError: 'int' object is not subscriptable
Run Code Online (Sandbox Code Playgroud)

当尝试使用库中的函数、方法或类时,我还看到了自定义消息。

什么是TypeError? 这样的消息是什么意思?我该如何理解并解决问题?


如果您的问题作为此问题的重复项而被关闭,请仔细阅读并遵循此处的建议,并在再次询问之前尝试调试代码并研究任何剩余问题。Stack Overflow 不是调试服务。

关于 a 的有效的、非重复的问题TypeError将询问为什么一个特定的、最小的、可重现的示例会导致 a TypeError,并解释您期望发生的情况以及原因。

Kar*_*tel 12

什么是TypeError?

它的含义正如其听起来的那样:存在由代码中的一个或多个值Error引起的。Type

...但是什么是“类型”?

在 Python 程序中,每个对象都有一个类型。“对象”(相当于 Python 中的“值”)是指可以在源代码中指定名称的东西。大多数名称都是简单变量:如果我们写x = 1,那么1是一个对象,它有一个名称x,它的类型是int- 类型本身有一个名称。

“类型”或多或少意味着它听起来的样子:它告诉你其他东西是什么样的东西。123均为整数;它们具有相同的类型,int。你可以把它想象成代表整数的概念。

并非每种类型都有内置名称。例如,函数是对象(大多数其他语言不是这样工作的!),并且它们有一个类型,但我们不能在代码中通过名称直接引用该类型。

然而,每种类型具有对象的表示形式,无论它是否被命名。您可以使用内置函数type来获取这样的“类型对象”:

>>> type(1) # the result from this...
<class 'int'>
>>> int # is the same:
<class 'int'>
>>> type(int) # We can look a bit deeper:
<class 'type'>
>>> def func():
...     pass
>>> type(func) # and get types that aren't named:
<class 'function'>
>>> type(type) # and there's this special case:
<class 'type'>
Run Code Online (Sandbox Code Playgroud)

值得注意的是, 的类型type type它本身

您可能会注意到,Python (3.x) 使用单词 来显示这些类型对象class。这是一个有用的提醒:当您创建 时class,您正在定义一种新的数据类型。这就是课程的目的。

这样的消息是什么意思?

我们可以将示例分为几类:

>>> type(1) # the result from this...
<class 'int'>
>>> int # is the same:
<class 'int'>
>>> type(int) # We can look a bit deeper:
<class 'type'>
>>> def func():
...     pass
>>> type(func) # and get types that aren't named:
<class 'function'>
>>> type(type) # and there's this special case:
<class 'type'>
Run Code Online (Sandbox Code Playgroud)

()这些异常告诉您用于调用func(或创建 的实例)的参数(您在 之间放置的内容MyClass)是错误的。要么太多,要么不够,要么没有正确标记。

诚然,这有点令人困惑。我们试图调用一个函数,而我们调用的是一个函数——所以类型实际上是匹配的。已确定的问题在于参数的数量。然而,Python 将其报告为 aTypeError而不是ValueError. 这可能是为了让来自其他语言(例如 C++)的程序员看起来更熟悉,其中“类型”在编译时进行检查,并且可能非常复杂 - 例如接受不同类型或数量的参数的函数本身被认为具有不同种类。

TypeError: func() takes 0 positional arguments but 1 was given
TypeError: func() takes from 1 to 2 positional arguments but 3 were given
TypeError: func() got an unexpected keyword argument 'arg'
TypeError: func() missing 1 required positional argument: 'arg'
TypeError: func() missing 1 required keyword-only argument: 'arg'
TypeError: func() got multiple values for argument 'arg'
TypeError: MyClass() takes no arguments
Run Code Online (Sandbox Code Playgroud)

这些异常告诉您运算符的左侧和右侧(如+or>或 之类的符号^,用于计算结果没有意义。例如,尝试对字符串进行除法或减法,或者将字符串重复非整数次,或者(在 3.x 中)将字符串与数字进行比较。作为一种特殊情况,您可以+在两个字符串(或列表或元组)之间使用,但它不会在数学意义上“添加”它们。如果尝试+在整数和字符串之间使用,错误消息将根据顺序而有所不同。

TypeError: unsupported operand type(s) for +: 'int' and 'str'
TypeError: can only concatenate str (not "int") to str
TypeError: '>' not supported between instances of 'int' and 'str'
TypeError: can't multiply sequence by non-int of type 'float'
TypeError: string indices must be integers
Run Code Online (Sandbox Code Playgroud)

这些有点棘手。该%运算符用于获取模数(数字相除时的余数),但也可以通过替换一些占位符来用于格式化字符串。(这是一个过时的系统,很难正确使用,并且有奇怪的特殊情况;在新代码中,请使用 f 字符串或.format方法。)

出现错误是因为左侧字符串中的占位符与右侧的占位符不匹配。在第二种情况下,您可能实际上想要计算模数,因此左侧应该是一个数字(很可能是一个整数)。这些是否应该改为 s 是有争议的,因为字符串的内容ValueError可能是错误的。然而,Python 无法读懂你的想法。

TypeError: %d format: a number is required, not str
TypeError: not all arguments converted during string formatting
Run Code Online (Sandbox Code Playgroud)

这也是一个运算符的问题,这次是[]运算符(用于对列表进行索引、对列表进行切片或在字典中查找键)。[]如果我们在以字符串为键的字典中查找键,那么字符串在 中是有意义的;但我们不能用它来索引列表。

TypeError: list indices must be integers or slices, not str
Run Code Online (Sandbox Code Playgroud)

这意味着错误的内容被传递给内置函数(或另一个可调用函数,例如类型)。从库中获取的函数可能会TypeError通过自定义消息引发自己的 s。该消息应该非常简单。

TypeError: int() argument must be a string, a bytes-like object or a number, not 'list'
TypeError: a bytes-like object is required, not 'str'
TypeError: bad operand type for abs(): 'str'
Run Code Online (Sandbox Code Playgroud)

这是非常不寻常的,大多数问这个问题的人永远不会遇到它(除了datetime标准库模块之外)。发生这种情况是因为尝试像使用函数一样使用方法,但给它提供了错误的类型self:例如,int.to_bytes('1')。该代码是错误的,因为'1'是一个字符串,而字符串不支持.to_bytes. Python 不会将字符串转换为整数;它不能给出 anAttributeError相反,因为是在类中to_bytes查找的,而不是在字符串上查找的。

TypeError: descriptor 'to_bytes' for 'int' objects doesn't apply to a 'str' object
Run Code Online (Sandbox Code Playgroud)

这些含义正是它们听起来的样子。“iterable”的意思是“能够被迭代”;即,反复检查以获得单独的值。这种情况发生在for循环、推导式以及尝试转换为列表时等。消息的“解包”变体是由于尝试在不可迭代上使用解包语法而产生的。

“callable”的意思是“能够被调用”;“调用”某个东西就是()在它后面写(可能在 之间有参数())。类似的代码1('test')没有意义,因为1它不是函数(或类型)。

“可订阅”是指“能够被订阅”;这里,“下标”意味着使用切片语法(x[1:2:3]),或者索引或查找键(x['test'])。我们只能使用序列(如lists 或strings)和映射(如dicts)来做到这一点。


Kar*_*tel 6

我该如何理解并解决问题?

首先,查看回溯以查看代码中发生错误的位置。如果它在库中,请向后工作到代码使用该库的位置。然后仔细阅读错误消息,并将其与代码进行比较,找出导致投诉的原因。最后仔细思考一下:是操作错误,还是价值观错误

例子

(去做)

一些不明显的事情

重复使用名称

您是否可能重新分配内置可调用对象的名称,例如stror inputor list?您是否尝试为两个不同的事物重用一个名称(例如,一个函数及其使用的一些全局数据)?

Python 中的名称一次只能指代一件事。如果您使用,例如,list作为变量名称,那么它不再是“列表的抽象概念”的名称,因此您不能使用它来创建更多列表(包括将其他内容转换为列表) )。如果您使用months字符串列表创建一个全局变量,然后编写一个函数months,该函数会替换该列表,并且该函数的代码无法查找该列表。使用from some_module import *语法时很容易意外发生这种情况。

同样,如果您尝试创建一个方法使用与实例的数据属性相同的名称的类,也会导致同样的问题。(还有一个棘手的特殊情况@staticmethod)。

处理列表

有时,人们期望能够像 Numpy 数组一样使用列表,并将操作函数调用“广播”到列表的每个元素。那是行不通的。请改用列表理解

处理None

考虑一下是否需要作为特殊情况来处理None。但首先要尽量避免陷入这种情况;正如他们所说,“特殊情况还不足以违反规则”。

尝试使用库(包括标准库)

如果某些事情没有像您期望的那样工作(例如,尝试减去datetime.times将用户定义类的实例序列化为 JSON) - 不要尝试将问题视为调试问题,而是搜索解决方案你想要那部分代码做的事

如果错误提到“str”类型,而您认为它应该是数字

你是从input函数中得到的吗?这会给你一个str,即使它看起来像一个数字。请参阅如何将输入读取为数字?

如果错误提到“function”类型或“type”类型

您是否忘记调用函数或创建类的实例?


有关错误参数的错误消息

错误消息会告诉你函数的名称;因此,请查看调用该函数的行的部分,并检查参数。位置参数的数量是否正确?是否存在必须提供但缺失的关键字参数?是否存在不应提供的关键字参数?是否有一个位置参数也由关键字提供?

如果您正在为类编写方法,请记住考虑到self. 对于实例方法来说这是必要的。如果您正在调用一个方法,请记住它将self被计为一个参数(“所需”数量和“给定”数量)。

classmethod初学者常见的一个错误是尝试使用类中的方法(不是)而不实例化它。你会做类似的事情

value = MyClass.method(things)
Run Code Online (Sandbox Code Playgroud)

你应该在哪里做类似的事情

instance = MyCLass()
value = instance.method(things)
Run Code Online (Sandbox Code Playgroud)

它(模糊地)instance作为第一个 ( self) 参数传递给method, 并things作为第二个参数。

如果您使用的回调从间接源获取参数,请检查源

如果您尝试创建自己的类的实例并获取 from TypeError__init__确保您确实编写了一个__init__.

如果您不知道参数应该是什么,请查看文档。如果参数有意义,则该函数可能是错误的 - 确保您没有将其与同一库中的另一个函数混淆。

有关操作数类型的错误消息

确保运算符对于您希望代码执行的操作正确无误(例如:^ 不是求幂;您想要**),然后检查操作数类型。

在大多数情况下,转换类型是合适的 - 但请仔细考虑。确保该操作对于新类型有意义。例如,如果代码是l + 'second',并且是当前包含 的la ,那么我们很可能不想连接字符串,而是创建一个也有作为元素的修改列表。所以实际上我们想“添加”另一个列表:。list['first']'second'l + ['second']

如果string indices must be integers,则被索引的字符串可能是 JSON或类似的东西,应该已经解析该字符串以创建字典(可能带有嵌套列表和字典)。

如果list indices must be integers or slices,则问题可能出在list,而不是索引。如果您期望list是 a dict,请检查它是否包含a dict- 特别是如果它只包含一个元素,即 a dict。然后检查这是否是dict真正应该研究的内容。如果是这样,解决方案很简单:只需添加另一个级别的索引,以便dict首先获取该索引。当尝试从解析的 JSON 中获取数据时,通常会发生这种情况。

有关字符串格式的错误消息

说真的,你打算进行字符串格式化吗?如果您确实想要格式化字符串,请考虑使用 f 字符串或.format方法- 这些更容易调试,并且特殊情况较少。但更有可能的是,左侧是一些类似的字符串'1',应该首先转换为int(或者可能 float)。

关于“描述符”的错误消息

Python 的错误消息相当晦涩难懂——它使用的术语是大多数程序员很少担心的。但一旦识别出来,错误就很容易进行模式匹配。如果可以在没有参数的情况下实例化该类,请特别注意 - 实例化该类仍然需要一对()括号;否则,代码引用类本身。需要一个实例才能使用方法。

来自内置函数的自定义错误消息

“一元”运算符(例如bad operand type for unary +: 'str')的“错误操作数”可能是由杂散逗号引起的'a', + 'b'不等于'a' + 'b'; 它试图用作字符串+上的一元运算符'b',然后创建一个元组。(你知道如何写eg-1来得到负数吗?-有一个一元运算符。事实证明你也可以类似地写;当然,+1它的意思与 相同。)1

特别是如果您必须将代码从 2.x 迁移到 3.x,请非常小心3.x 中的bytesstr类型之间的区别。bytes代表原始数据str代表文本。这些是根本不同且不相关的事物,只能通过使用编码从一种转换为另一种。在 Python 3.x 中,以二进制模式打开的文件('b'在模式字符串中使用)会bytes在读取时生成,并且必须在写入时提供与bytes写入时兼容的内容。str不符合资格;您必须显式指定编码。这个问题的典型是“TypeError: a bytes-like object is required, not 'str'” 在 Python 3 中处理文件内容时

某些内容“不”以某种方式可用的错误消息

你想这样使用它吗?

Python 无法读取你的意图。例如,访问列表的元素是使用[],而不是()。如果代码()相反,这将被解释为尝试调用列表,因此错误消息将抱怨该列表不可调用。

不可迭代

当某事发生时is not iterable,问题很可能出在该事物上,而不是迭代上。如果你想让一个for循环运行特定的次数,你仍然需要一些东西来迭代;arange是通常的选择。如果您使用列表理解等来制作值的多个副本,情况也是如此。如果你有一个整数x,并且想要创建一个包含一项的列表,即该整数,拼写为[x],而不是list(x)

尤其常见'NoneType' object is not iterable。只有一个'NoneType' object:特殊值None- Python 禁止创建该类的更多实例。就地工作的 Python 方法(尤其是列表方法)通常返回None而不是被修改的列表。另请参见TypeError: 'NoneType' object is not iterable in Python

不可调用

如果是 a 'module' object is not callable,很可能是因为您想要模块中的函数或类,该函数或类与模块同名,而不是模块本身。链接的示例适用于socket标准库;其他常见情况包括datetimerandom

还要确保代码不会调用函数并记住结果,而不是记住函数本身。这是需要“回调”函数的 API 的常见问题。(如果您需要提前选择参数,但实际上并不调用函数,请参阅如何将参数绑定到 Python 中的函数?。)有时人们也会尝试以字符串形式提供函数名称,而不是提供函数本身。

初学者有时希望能够在数学公式中进行“隐式乘法”,就像数学课上的那样。在 Python 程序中(与其他流行语言一样),类似的代码a(b + c) 不会将整数乘以;a的结果。b + c它尝试a像函数一样进行调用。请参阅为什么我会从“5(side_length**2)”这样的代码中收到“TypeError: 'int' object is not callable”?

不可订阅

有时,人们尝试通过对数字进行索引来从数字中获取“数字”,就好像它是一个字符串一样。int并且float不是字符串;他们里面没有数字。所以这会导致“不可下标” TypeError。无论以什么基数书写,数值都是相同的,并且除了以十为基数之外,还有其他书写方式;因此,您有责任首先创建适当的字符串。

如果您尝试使用嵌套列表,请小心对它们进行索引。像这样的列表example = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]应该像这样索引example[i][j]而不是例如example[i[j]]。这里的逻辑应该非常简单:正确的代码意味着索引example(获取整数列表),然后索引到该结果。由于括号的j嵌套方式,错误的代码意味着用作第一个索引。i

如果您尝试调用函数或使用类(例如内置range),请记住这使用括号,而不是方括号

# WRONG
range[10]
# RIGHT
range(10)
Run Code Online (Sandbox Code Playgroud)


归档时间:

查看次数:

8049 次

最近记录:

2 年,8 月 前