一、缘起
学生提交一个求列表元素之和的自定义函数,运行报错:
invalid character in identifier仔细检查代码,没错呀!可程序就是不能运行。折腾来折腾去,才发现是不间断空格惹的祸。
二、环境
Win7中文旗舰版64位 + Python 3.65 64位 + 8G RAM
三、出错代码
# 自定义函数:列表元素求和
def mysum(a):
n = len(a)
s = 0
for i in range(n):
s += a[i]
return s
if __name__ == "__main__":
print(mysum(1, 2, 5, 10))

根据之前的经验,代码中存在中文字符的时候,会提示这样的错误。看上图中暗红色的出错指示定位到了 s = 0 这一行。仔细看看,没有中文字符呀。不放心,切换到英文输入法,重新把 s = 0 敲了一遍。然后运行Python程序,还是出错。四、罪魁祸首
随后的半个小时里,一直在折腾。几乎把整个程序中的Python语句全敲了个遍,还是报错。当时根本就没有想到是看不见的空白字符存在问题。后来,突然想到,为什么提示函数体的第二行有问题,而函数体的第一行就没有问题呢?那我把第一行 n = len(a) 和 第二行 s = 0 前面的空白删掉,让第二行变成第一行,会怎么样呢?# 自定义函数:列表元素求和
def mysum(a):
s = 0
for i in range(n):
s += a[i]
return s
if __name__ == "__main__":
print(mysum(1, 2, 5, 10))
结果这次运行发现, s = 0 这一行没错了,又开始报告 for i in range(n): 这一行出错,还是同一个类型的错误:

这就有意思了。它不报告变量 n 不存在的错误,反而报告 invalid character in identifier ,不过这次换了一行报错。难道是函数体内各行前面的空白字符有玄机吗?于是回到最开始的代码,用文本编辑器Editplus打开程序代码文件,发现一个奇怪的现象:

以往在Editplus中打开Python代码文件,for、return、和print等关键字会显示成蓝色,这次居然毫无变化,更加怀疑是行首的空白字符有鬼。

在上图中,对比左边的十六进制字符和右边的程序代码,我们发现,函数体第一行语句 n = len(a) 的左边是四个半角空格字符(半角空格字符的ASCII码为32,对应的十六进制为20),而函数体第二行语句 s = 0 的左边是如下的一串字符(以十六进制表示):从IDLE代码编辑器中可以看出,这一串字符的显示效果相当于四个空格,于是,我们认为 C2 A0 是一个相当于空格的字符。那这个字符到底是什么字符呢?因为Python程序代码都是用UTF-8编码来存储的,所以我们只需要寻找UTF-8编码是 C2 A0 的字符就行了。这很好找:>>> b = b"\xc2\xa0"
>>> b.decode()
'\xa0'
于是,我们知道,函数体第二行语句 s = 0 的左边是四个字符'\xa0'。字符'\xa0'就是大名鼎鼎的不间断空格。五、代码修改
知道了程序出错的原因在于看起来是空格的不间断空格之后,我们修改程序就好办了,用替换功能把不间断空格替换为半角空格。这时候,Editplus编辑器中的三个关键字for、return、和print变成蓝色了:
运行程序,发现还是出错,因为调用函数mysum的时候传了四个整数参数过去,但定义函数mysum的时候只有一个形参a。我们把四个整数放在一个列表中就行了。正确的程序代码如下:
# 自定义函数:列表元素求和
def mysum(a):
n = len(a)
s = 0
for i in range(n):
s += a[i]
return s
if __name__ == "__main__":
print(mysum([1, 2, 5, 10]))
对于熟悉Python的同志们来说,可以用内置函数sum对自定义函数mysum进行简化,但对初学Python的同学来说,能写出这样的代码还算不错了。六、不间断空格
顺便说一下不间断空格。这个字符是ISO-8859-1字符集的一个字符。ISO-8859-1字符集是一个比较成功的ASCII字符集扩展方案。因为7位的ASCII字符集只有128个字符,字符数量远远不够用,于是人们想办法扩充ASCII字符集。比较有影响的扩充字符集有两个,一个是IBM437字符集,另一个是ISO-8859-1字符集。两个字符集都采用8位二进制数来表示字符,都兼容ASCII字符集。前者不是国际标准,目前已经很少使用,后者是国际标准,几乎所有的电脑都支持ISO-8859-1字符集。IBM437和ISO-8859-1这两个字符集都定义了不间断空格(Non-Breaking Space,NBSP)这个字符,不间断空格在Word中看起来像一个空心小圆圈,但从打印效果来看确实是空格,我们可以按住Ctrl+Shift+Space组合键来输入该字符。NBSP的作用是不让它两边的字符断开分在两行内。在HTML代码中,不间断空格就是用 来表示的。ISO-8859-1字符集是第一个被认定为国际标准的8位字符集,其全称是AmericanNational Standard for Information Processing-8-Bit Single-Byte Coded GraphicCharacter Sets-Part 1: Latin Alphabet No 1,所以该字符集又称为Latin-1。该字符集完全兼容ASCII,其对ASCII的扩展部分引入了32个控制字符、96个字母及符号,大部分使用拉丁字母的西欧语言都可以使用该字符集,因此该字符集又称为西欧字符集。该字符集的前32个码位(0x80~0x9F)跟ASCII一样,都设定为控制字符,接下来的一个码位0xA0仿照ASCII的空格字符0x20定义成不间断空格NBSP,余下的码位安排了95个图案字符。关于IBM437和ISO-8859-1这两个字符集,后面有机会会专门写一篇文章谈一下。这里说一下Word中的三类空格。七、Word中的三类空格
在Word中,有三类空格:半角空格,全角空格,不间断空格。如果Word设置成显示隐藏标记的话,我们会看到三类空格的形状如下:半角空格:显示成浅灰色的小圆点;
全角空格:显示成浅灰色的方框;
不间断空格:显示成小圆圈。
不间断空格是英文状态下为了防止单词换行时把一个词分成两行而发明的,在Word中按Ctrl+Shift+Space即可产生一个不间断空格。一般来说在中文文本中没啥用,从网页复制内容粘贴到Word里面的时候,可能会在Word文件中发现有不间断空格存在。在Word 2010中,打开和关闭隐藏标记的方法是:文件 --> 选项 --> 显示 --> “始终在屏幕上显示这些标记”条目下面有一些复选框,勾选相应的条目表示显示相应的隐藏标记,取消勾选则表示不显示相应的隐藏标记。
八、后记
欢迎指出本文的不足之处,欢迎就本文的相关问题跟作者进行交流。如果需要联系作者,请发邮件到 tbv_me@163.com 。