python2.7升级python3.5时,遇到的一些问题记录如下:
1. 字符串编码是最大的差别,py2的str为utf8编码,有单独的unicode类型,py3的str本身就是unicode编码,utf8则使用bytes类型。所以在py3里面没有unicode这种类型。以下是升级中遇到最蛋疼的麻烦:
>>> d = {'name': '张三'}
>>> b'name' in d
>>> False
2. s = 'abc',则s[0]为字符串'a';s = b'abc',则s[0]为整数97。
3. 在python2中是python -m SimpleHTTPServer,在python3里是python -m http.server
4. py3里没有xrange,只有range,而且返回为可用于迭代的对象。
5. map() zip() filter()也都返回迭代器对象,而不是列表,要得到列表需要写成list(zip(a,b)),包括dict.keys() dict.values() dict.items(),遍历不再需要写iteritems()了。所以map(lambda x : do_sth(x), [...])是不会依次全部执行的。
6. print支持f'{variable}xxx'写法 (py3.6才添加)
7. py2里的dict有clear()操作,但是list是没有的,如果要清空list,写法是del v[:],而在py3里list也添加了clear()方法。
8. py3里,Exception不能直接用索引取值了,需要使用使用args获利参数元组。即:
a = Exception(errno, errstr)
#py2
errno, errstr = a
#py3
errno, errstr = a.args
9. py3里dict没有has_key()方法,统一使用in表达式。
10. 在py2里有混乱的urllib、urllib2、urllib3,而在py3里全统一到urllib里了:
from urllib.parse import urlencode, parse_qs, urlsplit, quote, unquote
11. 整数除法有很大变化,py2整数相除得到还是整数,就像c/c++里一样,而py3则为小数,跟js类似,如果相除还想得到整数,就需要改成//相除。
12. 原来在py2里,4字节以内的整数类型为int,超过就是long,而py3里没有long类型,只有int,其实就是做了简化统一,而带来的问题是,大量整数计算时,py3要比py2占用更多内存,计算也明显更慢。
13. 在py3里,list的sort()没有cmp参数,而是通过key传入一个函数,为每个item生成一个key,再排序,每个key只生成一次。
14. 在py3里,只有input()来接收用户输入,而在py2里,有input()和raw_input(),其中input()相当于eval(raw_input(prompt))。为避免这种危险的函数,py3中就只有一个了,其input()就等同于py2中的raw_input()
15. 在py2里,file()和open()都是打开一个文件,通常你只关心打开模式为只读、读写,还是追加写,但在py3里,没有了file(),只有open(),而且你常常需要关心是否为二进制读或写,以得到bytes类型,从而提高效率。
16. 在py2里,有StringIO或者性能更好的cStringIO来在内存中做类似文件的读写,通常你需要优先import后者,失败时再import前者,而在py3里,统一到了io模块里,你需要考虑的是使用io.ByteIO还是io.StringIO。
17. 在py2里,你可以写next(iter(l)),或者写成iter(l).next(),但是在py3里,你只能用next(iter(l))。
18. 通常我们不用去管python内部的string intern机制,但intern()函数从py2里的全局函数变成了py3里的sys.intern()函数
19. py2里八进制写法为15==017,在py3里,八进制写法有些怪,为15==0o17
20. py3里的super()比py2里的更为强大,主要是支持无参数模式,而且其定义比较奇特:
super() -> same as super(__class__, <first argument>)
super(type) -> unbound super object
super(type, obj) -> bound super object; requires isinstance(obj, type)
super(type, type2) -> bound super object; requires issubclass(type2, type)
第二个默认参数为参数列表的第一个参数,这样,静态函数时就是cls,非静态函数就是self,这让几乎绝大多数情况下都不需要写参数了,例如如下静态函数重载的例子:
In [6]: class A:
...: name = 'A'
...: @classmethod
...: def run(cls, arg):
...: print(cls.name, arg)
In [9]: class B(A):
...: name = 'B'
...: @classmethod
...: def run(cls, arg):
...: super().run(arg)
...: print(cls.name, arg)
In [11]: B.run('abc')
B abc
B abc