我遇到了 TypeError。我该如何修复它?
- 2024-11-29 08:42:00
- admin 原创
- 159
问题描述:
我的 Python 代码中经常会出现未捕获的异常(错误),这些异常被描述为TypeError
s。经过大量的实验和研究,我收集了以下示例(和细微的变化):
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
当尝试使用库中的函数、方法或类时,我也看到了自定义消息。
什么是TypeError
?这样的消息是什么意思?我该如何理解和修复这个问题?
如果您的问题与此问题重复而被关闭,请仔细阅读并遵循此处的建议,并在再次提问之前尝试调试代码并研究任何剩余问题。Stack Overflow 不是调试服务。
关于的一个有效的、非重复的问题TypeError
将询问为什么一个具体的、最小的、可重现的例子会导致一个TypeError
,并解释您期望发生什么以及为什么。
解决方案 1:
什么是TypeError
?
它的意思正如其发音一样:存在由代码中的一个或多个值Error
的导致的。Type
...但是“类型”是什么?
在 Python 程序中,每个对象都有一个类型。我们所说的“对象”(在 Python 中等同于“值”)是指可以在源代码中命名的事物。大多数名称都是简单变量:如果我们写,x = 1
那么1
就是一个对象,它有一个名称x
,并且它的类型是int
- 类型本身有一个名称。
“类型”的意思大致就是字面意思:它告诉你其他东西是什么类型1
。 、2
和3
都是整数;它们具有相同的类型,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'>
值得注意的是, 的类型type
就是type
本身。
你可能会注意到,Python(3.x)用单词 来显示这些类型对象class
。这是一个有用的提醒:当你创建一个 时class
,你正在定义一种新的数据类型。这就是类的目的。
这样的信息意味着什么?
我们可以把这些例子分为几类:
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
()
这些异常告诉您,用于调用func
(或创建 的实例)的参数(您放在 之间的内容MyClass
)是错误的。要么参数太多,要么参数不够,要么标签不正确。
这确实有点令人困惑。我们试图调用一个函数,而我们调用的是一个函数 - 因此类型确实匹配。发现的问题在于参数的数量。但是,Python 将其报告为 而TypeError
不是ValueError
。这可能是为了让其他语言(如 C++)的程序员看起来更熟悉,其中“类型”是在编译时检查的,并且可能非常复杂 - 以至于接受不同类型或不同数量参数的函数本身被认为具有不同的类型。
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
这些异常告诉您运算符(用于计算结果的符号,如+
或>
或)的左侧和右侧没有意义。例如,尝试除或减字符串,或将字符串重复非整数次,或(在 3.x 中)将字符串与数字进行比较。在特殊情况下,您可以在两个字符串(或列表或元组)之间使用,但它不会在数学意义上“添加”它们。如果您尝试在整数和字符串之间使用,则错误消息将根据顺序而有所不同。^
`+`+
TypeError: %d format: a number is required, not str
TypeError: not all arguments converted during string formatting
这些有点棘手。%
运算符用于获取模数(除法时的余数),但它也可以用于通过替换一些占位符来格式化字符串。(这是一个过时的系统,很难正确使用,并且有奇怪的特殊情况;在新代码中,请使用 f 字符串或.format
方法。)
发生错误是因为字符串左侧的占位符与右侧的不匹配。在第二种情况下,您很可能实际上想要计算模数,因此左侧应该是一个数字(很可能是一个整数)。这些是否应该改为 s 是有争议的,因为字符串的内容ValueError
可能是错误的。但是,Python 无法读懂您的想法。
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
。从库中获取的函数可能会使用自定义消息引发自己的错误。消息应该非常简单明了。
TypeError: descriptor 'to_bytes' for 'int' objects doesn't apply to a 'str' object
这个问题很不寻常,问这个问题的大多数人都不会遇到(除非使用datetime
标准库模块)。发生这种情况是因为试图将方法用作函数,但为 提供了错误的类型self
:例如int.to_bytes('1')
。代码是错误的,因为'1'
是一个字符串,而字符串不支持.to_bytes
。Python 不会将字符串转换为整数;它不能给出 ,AttributeError
因为是在类中to_bytes
查找的,而不是在字符串中查找的。
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
这些含义与它们听起来的意思完全一致。“iterable”表示“能够被迭代”;即反复检查以获取单独的值。这种情况发生在for
循环、理解以及尝试转换为列表等时。消息的“unpack”变体是由于尝试在非可迭代对象上使用解包语法而导致的。
“callable” 表示“能够被调用”;“调用”某物就是()
在其后写入(可能在 之间带有参数()
)。像这样的代码1('test')
没有意义,因为1
它不是函数(或类型)。
“可下标” 表示“能够被下标”;此处,“下标” 表示使用切片语法 ( x[1:2:3]
),或索引或查找键 ( )。我们只能使用序列(如s 或ings)和映射(如s)x['test']
来执行此操作。list
`str`dict
解决方案 2:
我该如何理解并解决这个问题?
首先,查看回溯以查看错误发生在代码中的哪个位置。如果错误发生在库中,请反向查找到代码使用该库的位置。然后仔细阅读错误消息,并将其与代码进行比较,以找出导致投诉的原因。最后,仔细思考:是操作错误,还是值错误?
示例
(待办事项)
一些不太明显的事情
重复使用名称
您是否重新分配了内置可调用函数的名称,例如str
或input
或list
?您是否尝试将一个名称重用于两个不同的东西(例如,一个函数和它使用的某些全局数据)?
Python 中的名称一次只能指代一件事。如果您将其用作list
变量名,那么它就不再是“列表的抽象概念”的名称,因此您不能使用它来创建更多列表(包括将其他内容转换为列表)。如果您months
使用字符串列表创建一个全局变量,然后编写一个函数months
,则该函数将替换该列表,并且该函数的代码无法查找该列表。使用from some_module import *
语法时很容易意外发生这种情况。
类似地,如果您尝试创建一个类,使其方法的名称与实例的数据属性的名称相同,也会导致同样的问题。(还有一个棘手的特殊情况@staticmethod
)。
处理列表
有时人们希望能够使用像 Numpy 数组这样的列表,并向列表的每个元素“广播”操作或函数调用。这是行不通的。请改用列表推导式。
处理None
考虑是否需要将其None
作为特殊情况处理。但首先要尽量避免陷入这种情况;正如人们所说,“特殊情况还不足以打破规则”。
尝试使用库(包括标准库)
如果某些事情没有像您预期的那样工作(例如,尝试减去datetime.time
s或将用户定义类的实例序列化为 JSON) - 不要试图将问题视为调试问题,而是搜索您希望该部分代码执行的操作的解决方案。
如果错误提到“str”类型,而你认为它应该是一个数字
您是从函数中获取的吗?即使它看起来像数字,input
它也会返回一个。请参阅如何将输入读取为数字?。str
如果错误提到“函数”类型或“类型”类型
您是否忘记调用该函数,或者创建类的实例?
有关错误参数的错误消息
错误消息会告诉您函数的名称;因此请查看调用该函数的行部分,并检查参数。位置参数的数量是否正确?是否有必须提供但缺失的关键字参数?是否有不应提供的关键字参数?是否有也通过关键字提供的位置参数?
如果您正在为类编写方法,请记住允许self
。对于实例方法来说,这是必需的。如果您正在调用方法,请记住self
将被算作参数(对于“必需”的数量和“给定”的数量)。
初学者常犯的一个错误是尝试使用类中的方法(不是classmethod
),而不实例化它。你可以这样做
value = MyClass.method(things)
你应该做类似的事情
instance = MyCLass()
value = instance.method(things)
它(模糊地)instance
作为 的第一个(self
)参数传递method
,并things
作为 的第二个参数传递。
如果您使用从间接源获取参数的回调,请检查源。
如果您尝试创建您自己的类的实例并从中获取TypeError
,__init__
请确保您确实编写了一个__init__
。
如果你不知道参数应该是什么,请查阅文档。如果参数有意义,那么可能是函数错误 - 确保你没有将其与同一个库中的另一个函数混淆。
有关操作数类型的错误消息
确保运算符对于您想要代码执行的操作是正确的(例如:^
不是指数运算;您想要的**
),然后检查操作数类型。
在大多数情况下,转换类型是合适的 - 但请仔细考虑。确保操作对新类型有意义。例如,如果代码是l + 'second'
,并且l
是list
当前包含的['first']
,那么我们很可能不想连接字符串,而是创建一个也包含'second'
元素的修改列表。所以实际上我们想“添加”另一个列表:l + ['second']
。
如果string indices must be integers
,那么被索引的字符串可能是 JSON或类似的类型,应该已经对其进行了解析以创建字典(可能带有嵌套列表和字典)。
如果是list indices must be integers or slices
,问题很可能出在 而list
不是索引上。如果您预期 是list
,dict
请检查它是否包含——dict
尤其是如果它只包含一个元素,即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 中的bytes
和类型。表示原始数据;表示文本。 这些是根本不同且不相关的东西,只能通过使用编码将一个转换为另一个。 在 Python 3.x 中,以二进制模式打开的文件(在模式字符串中使用)在读取时会产生,并且必须在写入时提供与兼容的内容。不符合条件;您必须明确指定编码。在 Python 3 中处理文件内容时,此问题的典型示例是“TypeError:需要一个字节类对象,而不是‘str’”。str
`bytesstr
'b'bytes
bytes`str
错误消息,表示某些内容在某种程度上“不可”使用
你想以那种方式使用它吗?
Python 无法理解您的意图。例如,访问列表的元素是使用[]
而不是()
来完成的。如果代码()
中写着,则将被解释为尝试调用列表,因此错误消息将抱怨列表不可调用。
不可迭代
当某事 时is not iterable
,问题很可能出在该事上,而不是迭代上。如果您希望循环for
运行特定次数,您仍然需要迭代某事;通常的选择是 a 。如果您使用列表推导等来制作值的多个副本range
,情况也是如此。如果您有一个整数,并且想要制作一个包含一个项目的列表,即该整数,则拼写为,而不是。x
`[x]`list(x)
尤其常见'NoneType' object is not iterable
。只有一个'NoneType' object
:特殊值None
- Python 禁止创建该类的任何实例。就地工作的 Python 方法 -尤其是列表方法- 通常返回None
而不是修改后的列表。另请参阅TypeError:Python 中不可迭代的“NoneType”对象。
不可调用
如果是'module' object is not callable
,很可能是因为您想要模块中与模块同名的函数或类,而不是模块本身。链接的示例适用于socket
标准库;其他常见情况包括datetime
和random
。
还要确保代码不会调用函数并记住结果,而是记住函数本身。这是需要“回调”函数的 API 的常见问题。(如果您需要提前选择参数,但实际上并不调用函数,请参阅如何在 Python 中将参数绑定到函数?。)有时人们还会尝试将函数的名称作为字符串提供,而不是提供函数本身。
初学者有时希望能够在数学公式中进行“隐式乘法”,就像在数学课上那样。在 Python 程序中(与其他流行语言一样),像 这样的代码a(b + c)
不会将整数乘以a
的结果b + c
;它会尝试将a
其作为函数进行调用。请参阅为什么我会从像“5(side_length**2)”这样的代码中收到“TypeError:'int' 对象不可调用”?。
不可订阅
有时,人们会尝试通过对数字进行索引来获取“数字”,就好像它是字符串一样。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)
- 2024年20款好用的项目管理软件推荐,项目管理提效的20个工具和技巧
- 2024年开源项目管理软件有哪些?推荐5款好用的项目管理工具
- 2024年常用的项目管理软件有哪些?推荐这10款国内外好用的项目管理工具
- 项目管理软件有哪些?推荐7款超好用的项目管理工具
- 项目管理软件有哪些最好用?推荐6款好用的项目管理工具
- 项目管理软件哪个最好用?盘点推荐5款好用的项目管理工具
- 项目管理软件有哪些,盘点推荐国内外超好用的7款项目管理工具
- 项目管理软件排行榜:2024年项目经理必备5款开源项目管理软件汇总
- 项目管理必备:盘点2024年13款好用的项目管理软件
- 2024项目管理软件排行榜(10类常用的项目管理工具全推荐)