在编码过程中,调试代码占据了大部分时间,今天梳理下在 PyCharm 下调试代码的几个按钮的作用,以及常见的 Python 运行时错误。
图 1
我们在 PyCharm 运行代码时,可以通过上图中红色方框中的运行按钮。当然,如果代码中存在 “if name == 'main':” 语句,我们也可以点击其左边的运行按钮运行代码。需要注意的是,使用截图右上角红框中的运行按钮时,需要注意选择的是不是当前脚本,避免出现运行文件错误的情况。我在编码过程中,最常使用的是快捷键:"Ctrl+Shift+F10"
如果我们想要调试我们的代码,首先需要设置断点(在目标代码行左侧鼠标左击,会出现一个红色的点),然后点击调试按钮,调试按钮对应上图中的黄色方框,我们举例说明。
l = [1, 3, 2, 5, 0]
def bubble(l: list[int]) -> list[int]:
n = len(l)
for i in range(n):
for j in range(n - i - 1):
if l[j] > l[j + 1]:
l[j], l[j + 1] = l[j + 1], l[j]
return l
print(bubble(l))
如果我们想调试这个冒泡排序函数,那我们的断点可以打在函数的调用行,也就是"print(bubble(l))"所在行。我们也可以把断点打在函数内部,比如"n = len(l)"所在行。但是我们不能把断点打在函数定义行,也就是不能打在"def bubble(l: list[int]) -> list[int]:"行,因为如果在函数定义行打点,当调试器运行到函数定义处时,它将停在该处而不是在函数调用处停止,达不到预期效果。打完断点后,我们点击调试按钮即可。
在调试过程中,我们会使用到如下按钮,我们从左到右依次讲解:
图 2
为了方便演示,我们修改一下上面的代码。
import requests
l = [1, 3, 2, 5, 0]
def len_v2(l: list) -> int:
return len(l)
def bubble(l: list[int]) -> list[int]:
n = len_v2(l)
n2 = len([1, 2, 3])
n3 = requests.Session()
for i in range(n):
for j in range(n - i - 1):
if l[j] > l[j + 1]:
l[j], l[j + 1] = l[j + 1], l[j]
return l
print(bubble(l))
图 3
因为"len_v2"是我自定义的方法,所以第二次点击"Step Into"后,调试器阴影会定位到"len_v2"方法内的"return len(l)"所在行,如图 4。
图 4
第三次点击"Step Into"后,调试器阴影又回到"n = len_v2(l)"所在行。
第四次点击"Step Into"后,调试器阴影来到"n2 = len([1, 2, 3])"所在行。
第五次点击"Step Into"后,调试器阴影来到"n3 = requests.Session()"所在行,这时有小伙伴可以疑惑,为什么没有进入到"len()"函数内部呢?是因为"Step Into"按钮本应该进入 len 模块的代码并执行该函数。但是,PyCharm 默认设置了 “不进入 Python 库源代码” 的选项,所以调试器将跳过 len 模块的源代码并继续执行下一行代码。有伙伴可能会再次提问:Python 标准库都有哪些模块呢?我也为大家找到了查看 Python 标准库的方法,放在了文章末尾,有兴趣的小伙伴可以查阅。
第六次点击"Step Into"后,调试器会进入到"requests.Session()"内部,如图 5。这次为什么又进来了呢?因为 requests 是第三方模块,也是就需要我们"pip install"安装的模块。
图 5
我们一般不需要调试第三方库的代码,所以我们点击"Step Out"按钮,调试器阴影就会有回到"bubble()"函数的"n3 = requests.Session()"行。
后续再点击"Step Into",效果就和点击"Step Over"效果一样了。
Step Into My Code:左边第三个,单步跳入,快捷键:Alt+Shift+F7,和按钮"Step Into"唯一的区别是单击"Step Into"按钮时,调试器将进入当前代码行中调用的任何函数或方法,无论它们是来自您的代码还是来自第三方库,但是当单击"Step Into My Code"按钮时,调试器将仅进入当前代码行中调用的您自己编写的函数或方法,如果当前行中的调用来自第三方库,则调试器将跳过该调用并直接停在下一行。
具体表现为:相比上面"Step Into"的演示过程,这次只会进入我自定义的"len_v2()"函数内部,不会进入第三方模块"requests"内部。
Force Step Into:左边第四个,强制步入,快捷键:Alt+Shift+F7,用处不多,我几乎不用,所以不做过多介绍;
Step Out:左边第五个,跳过按钮,快捷键:Shift+F8,如果当前行位于函数内部,执行函数并跳过所有代码,直到该函数返回。这个很好理解,并且我们在演示"Step Into"按钮时就用到过,从"requests.Session()"内部跳回到"bubble()"函数。
Run To Curse:定位到游标处,快捷键:Alt+F9,调试器阴影直接切换到鼠标指定的地方。比如我们在调试"bubble()"时,虽然我们把断点打在了"print(bubble(l))"所在行,但如果我们将鼠标指针定位到"for i in range(n):"行后,点击"Run To Curse"按钮,那么调试器阴影直接切换到"for i in range(n):"行,跳过前面的步骤。
开门见山!
语法错误:无效语法
a === 1
print(a)
---------
File "G:\gxyPocket\PycharmProjects\TanAutoTools\debug_practice\practice.py", line 4
a === 1
^
SyntaxError: invalid syntax
缩进错误:意料之外的缩进
print(1)
--------
File "G:\gxyPocket\PycharmProjects\TanAutoTools\debug_practice\practice.py", line 4
print(1)
IndentationError: unexpected indent
缩进错误:缩进不匹配任何外部缩进级别
for i in range(5):
print(i)
print(i+1)
-----------------
File "G:\gxyPocket\PycharmProjects\TanAutoTools\debug_practice\practice.py", line 6
print(i+1)
^
IndentationError: unindent does not match any outer indentation level
缩进错误:期望一个缩进块
for i in range(5):
print(i)
-----------------
File "G:\gxyPocket\PycharmProjects\TanAutoTools\debug_practice\practice.py", line 5
print(i)
^
IndentationError: expected an indented block
类型错误:'list'对象不能被解释为整数
num=[1,2,3]
for i in range (num):
print(num[i])
----------------------
Traceback (most recent call last):
File "G:\gxyPocket\PycharmProjects\TanAutoTools\debug_practice\practice.py", line 6, in <module>
for i in range (num):
TypeError: 'list' object cannot be interpreted as an integer
类型错误:“str” 对象不支持项赋值
s = 'hello'
s[0] = 'H'
print(s)
---------
Traceback (most recent call last):
File "G:\gxyPocket\PycharmProjects\TanAutoTools\debug_practice\practice.py", line 5, in <module>
s[0] = 'H'
TypeError: 'str' object does not support item assignment
类型错误:不能将 “int” 对象隐式转换为 str
variable = '2'
variable += 1
--------------
Traceback (most recent call last):
File "G:\gxyPocket\PycharmProjects\TanAutoTools\debug_practice\practice.py", line 5, in <module>
variable += 1
TypeError: Can't convert 'int' object to str implicitly
语法错误:扫描字符串文字时出现 EOL
file_path = 'd:\'
-----------------
File "G:\gxyPocket\PycharmProjects\TanAutoTools\debug_practice\practice.py", line 4
file_path = 'd:\'
^
SyntaxError: EOL while scanning string literal
名称错误:名称 “fooba” 未定义
fooba()
--------
Traceback (most recent call last):
File "G:\gxyPocket\PycharmProjects\TanAutoTools\debug_practice\practice.py", line 4, in <module>
fooba()
NameError: name 'fooba' is not defined
属性错误:字符类型没有'lowerr'属性
s = 'hello'
s.lowerr()
----------
Traceback (most recent call last):
File "G:\gxyPocket\PycharmProjects\TanAutoTools\debug_practice\practice.py", line 5, in <module>
s.lowerr()
AttributeError: 'str' object has no attribute 'lowerr'
索引错误:索引越界
l = [1,2,3]
print(l[4])
----------
Traceback (most recent call last):
File "G:\gxyPocket\PycharmProjects\TanAutoTools\debug_practice\practice.py", line 5, in <module>
print(l[4])
IndexError: list index out of range
键错误:'zebra'
d = {'name':'Tom'}
print(d['zebra'])
--------------------
Traceback (most recent call last):
File "G:\gxyPocket\PycharmProjects\TanAutoTools\debug_practice\practice.py", line 5, in <module>
print(d['zebra'])
KeyError: 'zebra'
未绑定局部变量错误:局部变量'x'在赋值前被引用
x = 10
def my_func():
print(x)
x = 20
my_func()
--------------
Traceback (most recent call last):
File "G:\gxyPocket\PycharmProjects\TanAutoTools\debug_practice\practice.py", line 10, in <module>
my_func()
File "G:\gxyPocket\PycharmProjects\TanAutoTools\debug_practice\practice.py", line 7, in my_func
print(x)
UnboundLocalError: local variable 'x' referenced before assignment
类型错误:'range'对象不支持元素赋值
my_range = range(5)
my_range[0] = 1
-----------------------
Traceback (most recent call last):
File "G:\gxyPocket\PycharmProjects\TanAutoTools\debug_practice\practice.py", line 5, in <module>
my_range[0] = 1
TypeError: 'range' object does not support item assignment
类型错误:myMethod() 函数接受 1 个位置参数,但是给了 2 个
def myMethod(a):
return a
myMethod(1,2)
-------------------
Traceback (most recent call last):
File "G:\gxyPocket\PycharmProjects\TanAutoTools\debug_practice\practice.py", line 7, in <module>
myMethod(1,2)
TypeError: myMethod() takes 1 positional argument but 2 were given
Python 运行时常见错误差不多就这些,平时多和 Error 见见面,等调试的时候就不那么发憷了
打开 Python 官方文档网站 https://docs.python.org/3/library/ ,这是 Python 3 版本的标准库文档。如果您使用的是其他版本的 Python,请在网站的右上角选择相应的版本。
在页面左侧,您将看到一个包含所有标准库模块名称的列表。您可以单击列表中的任何模块名称,以查看有关该模块的详细文档。
如果您不知道要查找的模块的名称,可以使用文档中的搜索框。在搜索框中键入您要查找的模块名称或关键字,然后单击搜索按钮。文档将显示包含您的搜索关键字的所有模块的列表。单击列表中的任何模块名称,以查看有关该模块的详细文档。