难点和错误

做PythonABC基础教程时没有经验,没有提前写文案,直接录,所以很啰嗦内容水份很大。我其实是很想“毁尸灭迹”的,但因为脱水版要收费,所以免费版还是放在那儿,也许有人需要,虽然自己是不敢再看了。

生成PDF模块的第三方模块Reportlab剪切完毕,上传到网易云课堂和Udemy中文,课程介绍在这里:

制作这个教学视频花了大量时间剪辑,很不明智的选择。这个模块用得少,又有点复杂,我的方法也不对,到后面真是鸡肋。人到中年,四面八方都跟你要时间,都是“爷”哪个也耽搁不得,出于兴趣做的事优先级只好排在最末,当然这都是借口,主要还是逮着时间就像玩,反正是硬着头皮做完的。

接下来会做PythonABC基础教程的脱水版,弥补一下缺憾,更新一下内容。另外暂时没有办法答疑,抱歉抱歉。想赶紧(呃,内个,尽量尽量哈)把脱水版做完,做moviepy这个模块,我被reportlab的视频剪辑弄得痛苦不堪,要找一个视频处理的模块,希望能提高工作效率。另外以后介绍第三方模块也不再里里外外上上下下都介绍,耗时费力,专注常用部分。

这个初学者错误的视频是脱水版的,分享出来一个是觉得可能有些用处,再一个上一个视频解释系统中彻底删除python,有朋友调侃是结束:

不是,其实是我在录制脱水版安装第三方模块时讨厌自己电脑上装了好几个版本的python,想先彻底删除,而后装自己中意的版本,是有“而后”哒。拉回正题,先分享初学者常犯错误的文案,再上视频。

 

列出一些初学者常犯的错误供参考:

 

  • 第一道拦路虎

对于第一次接触Python并用PyCharm作为开发平台的人,遇到的第一个问题可能是忘记配置Python解释器。此时,如果是在Mac上就选择“PyCharm”菜单的“Preferences”;在Windows上就从菜单“File”中选择“Settings”。弹出窗口左栏中的项目名称旁边有个三角按钮,单击展开内容,选择“Project Interpreter”,查看右栏的项目解释器(Project Interpreter),从下拉框里选择Python 3.X版本。

还有一种张冠李戴情况经常发生,不能算是程序错误,但有时会困扰初学者。比如在PyCharm上调试li.py这个程序,却发现运行结果不合乎逻辑。这时请检查绿色运行按钮旁边的程序名称,确认运行的是li.py而不是之前运行的zhang.py。

 

  • 丢三落四

1.忘记在if、elif、else、for、while、class、def声明末尾添加“:”,如:

if spam == 42
    print('Forget colon')

42后会有一个小小的红色波浪线,提示此处有语法错误。执意运行会出现错误提示

SyntaxError :invalid syntax

改正办法就是在42的后面加上“:”。

2.条件表达式中判断是否相等使用 “==”,而不是赋值号“=”,否则会出现

SyntaxError: invalid syntax

的错误。

3.忘记在字符串首尾加引号,如:

print('Hello)

错误提示为

SyntaxError: EOL while scanning string literal

又例如:

myName = 'Thranduil'
print('I am ' + myName + 'Elf's king')

错误提示为

SyntaxError: invalid syntax

改成:

print('I am ' + myName + 'Elf's king')

此时还是出错,错误提示为

SyntaxError: invalid syntax

因为字符串里的单引号'算特殊字符,需要做特殊处理,所以在前面加一个转义字符\:

print('I am' + myName + 'Elf\'s king')

或者换掉字符串的界定符:

print('I am' + myName + "Elf's king")   

4.忘记将方法函数的第一个参数设置为self,如:

class Performer(object):
    def myDeclaration():
        print('其实我是一名演员')
a = Performer()
a.myDeclaration()

错误提示为

TypeError: myDeclaration() takes 0 positional arguments but 1 was given

即函数没有形参,调用时却给了一个实参,原因在于函数myDeclaration()不是普通函数,而是类里的方法函数。类里的方法函数有3类:对象的方法函数、类的方法函数和静态函数。对象的方法函数第一个形参必须为self,调用时不用给self传入实参。所以myDeclaration()也应该有个形参self与之对应,即:

def myDeclaration(self):

如果没有就会出现形参与实参不匹配的错误。

5.调用模块内的函数时不在前面加模块前缀,如:

import math
print(ceil(4.5))

错误提示为

NameError: name 'ceil' is not defined

只要在ceil前加模块前缀math.ceil(4.5)就可以了。又如:

import time
print(time())

错误提示为

TypeError: 'module' object is not callable

错误提示虽然不同,实质上是一样的错误,都是调用模块内函数不在前面加模块,用time.time()可更正。出现这个错误提示是因为刚好要调用的函数跟模块同名,错误提示提醒模块是不能调用的。

有一种办法可以省却每次调用都要添加模块前缀的麻烦,就是把“import 第三方模块”的格式换成“from 第三方模块 import *”。这种方法的缺点是对引入的函数来自哪个模块不能一目了然,也可能出现不同模块的函数同名冲突的情况,影响代码的稳定性。

  • 无中生有

1.使用不存在的字典键,如:

dict1 = {'cat':'黑猫警长', 'dog':'卡尔', 'mouse':'米老鼠'}
print('我的宠物斑马叫 ' + dict1['zebra'])

错误提示为KeyError: 'zebra'。因为字典dict1里根本没有'zebra'这个键。改正办法是增加'zebra'键,或者换成已有键。

2.Python中不存在 ++自增和--自减操作,如:

m = 1
m++

错误提示是

SyntaxError: invalid syntax

把m++改成

m += 1

即可。

  • 强人所难

1.尝试修改字符串的值:

str = '春风又到江南岸'
str[3] = '绿'
print(str)

运行这段代码会出现错误提示:

TypeError: 'str' object does not support item assignment

因为str是字符串,字符串是一种不可变的数据类型,元组(tuple)也是不可变数据类型,给字符串或元组赋值相当于给一个常数赋值。可用下列语句替换掉字符串里的“到”:

str = str[:3] + '绿' + str[4:]

str内容现在被修改为“春风又绿江南岸”。

2.尝试将非字符串值与字符串进行连接:

numEggs = 12
print('I have ' + numEggs + 'eggs.')

得到的错误提示是

TypeError: must be str, not int

“+”可以连接两个字符串,可以相加两个数值,但是不能连接数值和字符串。可以用占位符解决:

print('I have {} eggs.'.format(numEggs))

也可以用逗号分隔数值和字符串,输出时会以空格分离:

print('I have', numEggs, 'eggs')

两条print语句的运行结果都是:

    I have 12 eggs

3.对新变量使用增值操作符“+=”。eggs在程序中的第一次亮相是出现在eggs += 42中,运行的错误提示为

NameError: name 'eggs' is not defined

因为eggs+=42等同于eggs = eggs + 42,eggs需要指定一个有效的初始值。

4.使用函数range()时,实参给列表,如输出列表索引和元素:

list1 = ['cat', 'dog', 'mouse']
for i in range(list1):    
    print(i, list1[i])

错误提示是

TypeError: 'list' object cannot be interpreted as an integer

因为range()要求的参数是整数,这里却给了一个list类型的实参。这段代码有两个更正办法,一个是满足range()参数要求传入整数:

for i in range(len(list1)):
    print(i, list1[i])

另一个是for循环直接用列表,用列表的方法函数index()把指定索引的值输出:

for item in list1:
    print(list1.index(item), item)

用enumerate()列举也可以:

for i,v in enumerate(list1): 
    print(i, v)

5.尝试使用range()创建整数列表:

s = range(10)
s[4] = -1

错误提示为

TypeError: 'range' object does not support item assignment

本来是希望得到一个有序的整数列表,range() 看上去是生成此列表的不错方式。可是range()返回的是range对象,不是想要的列表,想变成列表需要多一个列表转换的操作,即把s = range(10)替换成:

s = list(range(10))

6.局部变量与全局变量重名的情况下,在定义局部变量的函数中没有给局部变量赋值就    试图去读取局部变量的值。下面这段代码没问题:

someVar = 42
def myFunction():
    print(someVar)myFunction()

someVar是全局变量,作用域涵盖了整个myFunction(),即在myfunction()函数内访问someVar没有问题。下面的代码也没问题:

someVar = 42
def myFunction():
    someVar = 40
    print(someVar)
myFunction()

函数myFunction()内定义了与全局变量同名的局部变量someVar,函数内局部变量屏蔽了全局变量。但下面的代码有问题:

someVar = 42
def myFunction():
    print(someVar)
    someVar = 100
myFunction()

错误提示为

UnboundLocalError: local variable 'someVar' referenced before assignment

函数myFuction()内没有对局部变量赋值就对它进行了读取,myFunction()函数是局部变量someVar的作用域,在这个区域内全局变量someVar被屏蔽。更详细可参见5.4节变量作用域和不确定个数形参。

7.引用对象没有的属性或方法函数:

myList = ['bacon', 'apple', 'strawberry', 'durian', 'cherry']
myList.order()

错误提示为

AttributeError: 'list' object has no attribute 'order'

列表没有方法函数order(),排序应该用

myList.sort()
  • 无心之失

1.尝试使用Python关键字作为变量名:

class = 3

错误提示为

SyntaxError: invalid syntax

class是Python关键字,定义类时使用,不能用作变量名。Python不能用关键字作变量名、函数名。

Python3的关键字有:

跟条件判断有关的if、elif、else、True、False、and、or、not、is、None;

处理意外的try、except、finally、raise、assert;

函数和类定义用得比较多的pass、def、class、global、nonlocal、lambda、return;

循环用的for、in、while、yield(生成器)、break、continue;

引入模块用到的from、import;不太好分类的as、del、with。 

2.所在文件夹下有跟引入模块名字相同的代码文件。假设有段代码应用logging模块启动日志:

import logging
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s')  
… 

运行时却出现

AttributeError: module 'logging' has no attribute 'basicConfig'

的错误,错误行指向logging.basicConfig这一行。错误原因可能是代码文件所在的文件夹下有个名为logging.py的代码文件,并且当前目录已经加入Python解释器的搜索路径内。Python解释器认为import logging是引入了自己定义的logging.py,解决办法就是改掉当前文件夹下logging.py的名字。

3.Python用缩进来标识程序块,没有程序块起始和结束的标志。同一缩进层次的连续代码被视作一个程序块。Python规定缩进是4个空格,错误地使用缩进会引发错误:

print('Hello')
    print('Howdy')

出现缩进错误

IndentationError:unexpected indent

提示在不该缩进的位置缩进了。又如下面的代码:

if spam == 42:
    print('Hello!')              # 缩进用4个空格。
    print('Howdy!')              # 用Tab键添加的缩进。

第一个print语句后会有个小红色波浪线,第二个print前有个不同颜色的小块,运行则会出现

IndentationError:unindent does not match any outer indentation level

的错误。原因就是缩进方法不统一,有的用4个空格,有的用Tab键。解决办法就是在PyCharm的“Edit”菜单下选择“convert indents”,再选择“To Spaces”,将缩进方式统一成4个空格。

再看以下代码:

if spam == 42:
print('Hello!')
print('Howdy!')

错误提示是

IndentationError:expected an indented block

跟在if语句后面的语句该有的缩进没有,加上缩进就可以了。缩进增加只用在以“:”结束的语句之后,程序块结束后的语句要恢复到原来的缩进。

4.Python程序用到的符号(单引号、双引号、括号……)要在英文输入法下输入,如果在中文输入法下输入,虽然看起来一样,但程序运行却会报错。这种错误在字符串里有中文字符,输入法不得不切来切去时很容易发生,例如:

print(‘爱睡懒觉的猫‘)

看起来没有问题,忽略语法检查通不过的红色波浪线强行运行时会出现

SyntaxError: invalid character in identifier

的错误。原因就是用了中文输入法下的括号,切成英文输入法下的括号:

print('爱睡懒觉的猫')

就恢复正常了。

  • 粗心大意

1.变量或者函数名拼写错误:

guest = 'Al'
print('Name of guest is ' + gues)
# NameError: name 'gues' is not defined,变量名拼写错误。 

s = ruond(4.2)
# NameError: name 'ruond' is not defined,本意是要应用内置的四舍五入函数round(4.2)。 

s = Round(4.2)
# NameError: name 'Round' is not defined,Python对大小写敏感。 

str1 = "Convert me to LOWERCASE"str1 = str1.lowerr()
# AttributeError: 'str' object has no attribute 'lowerr',
# 错误提示是字符串对象没有lowerr这个属性或方法函数,
# 改成str = str.lower()即可。

2.Python的字符串、元组和列表的索引都是从0开始的,注意引用时不要超过最大索引:

list2 = ['cat', 'dog', 'mouse']
print(list2[3])
# IndexError: list index out of range,list2的最大索引为2。

3.函数形参与实参个数不符:

def addValue(x):
    sum = 0
    sum += x
    return sum
x, y = 3, 4
addValue(x, y)

错误提示为

TypeError: addValue() takes 1 positional argument but 2 were given

意思是函数addValue()只有一个形参,现在却给了两个实参,实参与形参个数不符。

5.该安装的没安装,该引入的没引入:

如果没有引入time模块,在代码中使用time.time(),就会出现错误提示:

NameError: name 'time' is not defined

time这种Python自带的模块不必安装,但在程序中使用必须先import导入才行。

若引入的是第三方模块则在引入前需要先安装,否则会出现:

ModuleNotFoundError: No module named 'PyAutoGUI'

的错误(PyAutoGUI是试图导入的第三方模块)的错误。若引用自写的.py文件里的函数或数据,需要把.py文件所在目录加进Python解释器搜索路径中,参见引入自定义模块时提示找不到

代码写出来没有语法错误才是万里长征的第一步,语法错误容易解决,而逻辑错误难查找。第三方模块帮我们实现了很多功能,而且无须操心复杂的实现细节,“直接拿来用”就可以了。不好的地方是一旦出了问题会很被动,技术细节都被封装起来,加大了查找定位错误所在的困难。排错时要善用互联网资源,一般使用的排错方法是:将错误提示直接复制到搜索引擎,从而找到很多有助于纠错的宝贵信息。

PythonABC致力于介绍有趣的、有用的、有料的第三方模块