1. Python 2 None 对象无 __eq__ 方法的原因分析
Python2.7: typeobject.c 里面 PyBaseObject_Type 结构体 tp_richcompare 成员为 0
而在 Python 3.x 的代码里面这个成员的值是 object_richcompare
当 attr 的查找进入 __getattr__ 中,Python 按 __mro__ 来依次寻找,None 的 __mro__ 是
(NoneType, object),在 C 实现中,前者是 PyNone_Type,后者是 PyBaseObject_Type 。这两个类的
__dict__ 中都没有 __eq__ 这个 key,所以查找失败,raise AttributeError.
但是 object.__eq__ 却又能成功,那是因为 object 的类型是 type ,type.__dict__ 中就有 __eq__ 这个 key。有点绕。但通过这件事可以知道 NoneType 是一种“特殊”的类型。
2. Python 2 终端、文件编码问题
在交互式命令模式(Interactive shell)下:
>>> import sys >>> sys.stdout.encoding
在 Windows 下,如果你的系统是简体中文,一般输出会是 cp936
>>> import codecs >>> codecs.lookup('cp936').name 'gbk'
这就是在 Windows 终端里面使用的编码。在 print 的时候,无论字符串源采取什么样的编码,最终输出的字符串的编码必须跟 shell 的编码一致,也就是说:
>>> print some_string
Python 会做这样一个动作:
codecs.encode(some_string, coding, errors='strict')
当 some_string 是一个 unicode 字符串,coding 是 gbk, some_string 里面包含 gbk 字符集里面没有的字符,Python 就会抛出一个 UnicodeEncodeError.
对于输出到文件中情况是类似的,Python2 的 open() 函数不会传入 encoding,以 'w' 方式打开文件,如果写入
unicode 字符串,Python 会获取当前默认的编码,然后以此种编码把字符串写入文件。可惜的是,“默认编码”只是 Python
自己默认的,在 Objects/unicodeobject.c 中,用一个全局变量 unicode_default_encoding
来表示默认的编码:
/* Default encoding to use and assume when NULL is passed as encoding parameter; it is initialized by _PyUnicode_Init(). Always use the PyUnicode_SetDefaultEncoding() and PyUnicode_GetDefaultEncoding() APIs to access this global. */ static char unicode_default_encoding[100 + 1] = "ascii";
这个值在 Python 中有C接口(PyUnicode_SetDefaultEncoding)去改变, Python 层的接口:
>>> sys.setdefaultencoding(coding)
但需要在编译时增加 Py_USING_UNICODE 宏的定义,官方发布的 Windows 版本没有这个功能。
所以在调用到类似 file.write(some_string) 的时候,首先会有这样的编码过程:
codecs.encode(some_string, coding, errors='strict')
当 some_string 是一个 unicode 字符串,并且包含 ascii 字符集不存在的字符时,就会抛出一个 UnicodeEncodeError。
所以,为了解决这个问题,可以这么处理:
(1) 在 Windows shell 下面:
>>> print some_string.encode('gbk', errors='ignore') # replace 也可,只要不是 strict
(2) 在写入文件时,两种方法:
a. 忽略不存在的字符,同(1)
>>> f = open(filename, 'w') >>> f.write(some_string.encode('gbk', errors='ignore')
b. byte 方式写入:
>>> f = open(filename, 'wb') >>> f.write(some_string.encode('utf-8'))
a 会损失字符,b 不会。