如何理解并解决问题?
首先,查看回溯以确定错误发生的代码位置。如果是在库中,反推到您的代码使用该库的地方。然后仔细阅读错误消息,并将其与代码进行比较,以确定引起投诉的原因。最后,请认真思考:操作有误还是值有误?
示例
(待定)
一些不明显的事情
重复使用名称
您是否重新分配内置可调用函数的名称,例如 str
或 input
或 list
?您是否尝试为两个不同的事物重复使用名称(例如函数和一些它使用的全局数据)?
Python中的名称一次只能引用一个东西。如果您使用例如
list
作为变量名,那么它就不再是“列表的抽象概念”的名称,因此您不能使用它来创建更多的列表(包括将其他内容转换为列表)。如果您创建了一个具有字符串列表的全局变量
months
,然后编写一个名为
months
的函数,则该函数将替换列表,并且函数的代码无法查找列表。这很容易在意外情况下发生
当使用from some_module import *
语法时。
同样,如果您尝试创建一个类
使用与实例的数据属性相同的方法名称,那么也会导致同样的问题。(还有一个
带有@staticmethod
的棘手特殊情况)。
处理列表
有时人们期望能够像使用Numpy数组一样,将操作或函数调用“广播”到列表的每个元素上。但是这是行不通的。使用列表推导式代替。
处理None
考虑是否需要将None
作为特殊情况处理。但是尽量避免首先进入这种情况;正如所说的,“特殊情况不足以打破规则”。
尝试使用库(包括标准库)
如果某些东西不像您期望的那样工作(例如,尝试从时间中减去datetime.time
或将用户定义类的实例序列化为JSON)-而不是试图将问题视为调试问题,请搜索解决方案以满足您希望该部分代码完成的内容。
如果错误提到了“str”类型,而你认为它应该是一个数字
你是不是从input
函数中获取的?这会给你一个str
类型,即使它看起来像一个数字。请参见如何将输入读取为数字?。
如果错误提到了“function”类型或“type”类型
你是否忘记调用函数或创建类的实例?
关于错误参数的错误信息
错误信息会告诉你函数的名称;因此,请查看调用该函数的行的部分,并检查参数。是否有正确数量的位置参数?是否需要提供关键字参数,但缺少了?是否提供了不应该提供的关键字参数?是否提供了由关键字和位置两种方式提供的参数?
如果您正在为类编写方法,请记得允许使用 self
。这对于实例方法是必要的。如果您正在调用方法,请记住self
将被计算为一个参数(既适用于“所需”的数量,也适用于“给定”的数量)。
一个常见的初学者错误是尝试在没有实例化的情况下使用类中的方法(它不是一个classmethod
)。您可能会做一些像这样的事情:
value = MyClass.method(things)
你应该做类似这样的事情
instance = MyCLass()
value = instance.method(things)
这段代码(含糊不清地)将instance
作为第一个(self
)参数传递给method
,将things
作为第二个参数。
如果您正在使用从间接来源获取参数的回调,请检查来源。
如果您尝试创建自己类的实例,并从__init__
获得TypeError
,请确保您实际编写了__init__
。
如果您不知道参数应该是什么,请检查文档。如果参数有意义,也许函数是错误的 - 确保您没有将其与同一库中的另一个函数混淆。
关于操作数类型的错误消息
确保运算符对于您想要代码执行的操作正确(例如:^
不是指数运算;您需要**
),然后检查操作数类型。
在大多数情况下,转换类型是合适的 - 但要仔细考虑。确保操作与新类型一起有意义。例如,如果代码是
l + 'second'
,而
l
是当前包含
['first']
的
list
,那么很可能我们不想连接字符串,而是创建一个修改后的列表,其中也有
'second'
作为元素。因此,实际上我们想要
"添加" another list:
l + ['second']
。
如果
string indices must be integers
,那么被索引的字符串可能是JSON或类似的东西,应该已经解析为字典(可能带有嵌套的列表和字典)。
如果出现“列表索引必须是整数或切片”错误,很可能问题出在列表本身,而不是索引上。如果你期望的列表是一个字典,请检查它是否包含一个字典——特别是如果它只包含一个元素,而这个元素是一个字典。然后检查是否应该查找的确实是这个字典。如果是这样,解决方案很简单:只需添加另一层索引,以便首先获取那个字典。这通常发生在尝试从解析的JSON中获取数据时。
关于字符串格式的错误消息
说真的,你是想做字符串格式化吗?如果确实想要格式化一个字符串,考虑使用f-strings或者.format()方法。这些方法更容易调试,也没有太多特殊情况。但更可能的情况是,左边的部分是一些字符串,比如'1'
,本应该先转换为int
(或者可能是float
)。
关于“描述符”的错误信息
Python的这个错误消息相当难以理解——它使用了大多数程序员很少或者从未遇到的术语。但是,一旦被认出来,这个错误就变得非常容易匹配。特别注意,如果类可以不带参数实例化,则需要一个空括号 ()
才能实例化该类;否则,代码将引用类本身。必须有一个实例才能使用方法。
内置函数的自定义错误消息
一个“一元”运算符的“错误操作数”(例如
bad operand type for unary +: 'str'
)
可能是由于一个杂项逗号引起的。
'a', + 'b'
不同于
'a' + 'b'
;它试图在
'b'
字符串上使用
+
作为一元运算符,然后生成一个元组。(你知道你可以写例如
-1
来得到一个负数吗?那里的
-
是一个
一元运算符。当然,你也可以类似地写
+1
;它的意思和
1
是一样的。)
特别是如果你不得不从2.x迁移代码到3.x,一定要非常小心区分3.x中bytes
和str
类型之间的区别。 bytes
表示原始数据; str
表示文本。这些是根本不同且无关的事情,只有通过使用编码才能从一个转换为另一个。在Python 3.x中,以二进制模式打开的文件(在模式字符串中使用'b'
)读取时会产生bytes
,写入时必须给出与bytes
兼容的内容。 str
不符合条件;您必须明确指定编码。处理Python 3中的文件内容时,此问题的规范是{{link1:“TypeError:a bytes-like object is required, not 'str'”}}。
某些东西“不可用”的错误消息
您想以这种方式使用它吗?
Python无法读取您的意图。例如,访问列表元素使用[]
而不是()
。如果代码使用()
,那么它将被解释为尝试调用列表,因此错误消息将抱怨列表不可调用。
不可迭代
当某物不可迭代
时,问题很可能出在该物体上,而不是迭代上。如果您想要一个for
循环运行特定次数,仍然需要有东西进行迭代;range
通常是选择。如果您正在使用列表推导等来制作多个值的副本。如果您有一个整数x
,并且您想要制作一个只包含该整数的列表项的列表,那么应该写成[x]
,而不是list(x)
。
在编程中,经常会看到'NoneType' object is not iterable
。实际上只有一个'NoneType' object'
:特殊值None
- Python禁止创建该类的任何其他实例。Python中的原地操作方法 - 尤其是列表方法 - 通常返回修改后的列表而不是None
。另请参见Python中的TypeError:'NoneType' object is not iterable。
不可调用
如果'module' object is not callable
,最可能的原因是您想要从模块中获取与模块同名的函数或类,而不是模块本身。链接的示例是标准库socket
;其他常见情况包括datetime
和random
。
同时确保代码不要调用函数并记住结果,而是记住函数本身。这是API常见的问题,它希望有一个“回调”函数。(如果您需要提前选择参数,但实际上不需要调用函数,请参见如何在Python中绑定函数参数?。)有时人们也会尝试提供函数名作为字符串, 而不是提供函数本身。
初学者有时期望在数学公式中能够进行“隐式乘法”,就像在数学课堂上一样。 在Python程序(像其他流行的语言一样),代码如a(b + c)
不会将整数a
乘以b + c
的结果;它试图调用a
,就像它是一个函数一样。 请参见为什么我会从像"5(side_length**2)"这样的代码中得到“TypeError:'int' object is not callable”错误消息?。
不可订阅
有时候,人们试图通过像字符串一样索引数字来获取“数字”。
int
和
float
值
不是字符串;它们里面没有数字。因此,这将导致“is not subscriptable”
TypeError
。无论您用什么基数编写数字,其数值都是相同的,并且除了十进制之外,还有其他编写数字的方法;因此,您需要先创建适当的字符串。
如果您正在尝试使用嵌套列表,请小心索引它们。像
example = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
这样的列表应该像
example[i][j]
这样索引,而不是像
example[i[j]]
这样。这里的逻辑应该很简单:正确的代码意味着要索引到
example
(获取整数列表),然后再索引到该结果。不正确的代码意味着首先使用
j
作为
i
的索引,因为括号是嵌套的。
如果你想调用一个函数或使用一个类(例如内置的range
),请记住使用圆括号而不是方括号:
range[10]
range(10)
TypeError
的简单问题。请不要尝试将其关闭为其他内容的副本;这里的目标是足够一般地描述TypeError
以涵盖常见问题,同时仍然对所有问题提出相同的问题。请参见我遇到了IndentationError。我该如何解决?以获取先例。此答案也至少部分存在于帮助找到特定TypeError
原因的更多特定规范方面。 - Karl KnechtelNoneType
是一种类型,而不是一个错误;可能会有多个TypeError
提到它(更不用说AttributeError:'NoneType'对象没有属性'foo'
了,这比那些常见得多)。然而,你当然可以自由地起草自己的规范。 - Karl Knechtel