2024年6月4日发(作者:)
Python3.x和Python2.x的区别
1.性能
Py3.0运行 pystone benchmark的速度比Py2.5慢30%。Guido认为Py3.0有极大的优化空间,在字符串和整形操作
上可
以取得很好的优化结果。
Py3.1性能比Py2.5慢15%,还有很大的提升空间。
2.编码
Py3.X源码文件默认使用utf-8编码,这就使得以下代码是合法的:
>>> 中国 = 'china'
>>>print(中国)
china
3. 语法
1)去除了<>,全部改用!=
2)去除``,全部改用repr()
3)关键词加入as 和with,还有True,False,None
4)整型除法返回浮点数,要得到整型结果,请使用//
5)加入nonlocal语句。使用noclocal x可以直接指派外围(非全局)变量
6)去除print语句,加入print()函数实现相同的功能。同样的还有 exec语句,已经改为exec()函数
例如:
2.X: print "The answer is", 2*2
3.X: print("The answer is", 2*2)
2.X: print x, # 使用逗号结尾禁止换行
3.X: print(x, end=" ") # 使用空格代替换行
2.X: print # 输出新行
3.X: print() # 输出新行
2.X: print >>, "fatal error"
3.X: print("fatal error", file=)
2.X: print (x, y) # 输出repr((x, y))
3.X: print((x, y)) # 不同于print(x, y)!
7)改变了顺序操作符的行为,例如x 8)输入函数改变了,删除了raw_input,用input代替: 2.X:guess = int(raw_input('Enter an integer : ')) # 读取键盘输入的方法 3.X:guess = int(input('Enter an integer : ')) 9)去除元组参数解包。不能def(a, (b, c)):pass这样定义函数了 10)新式的8进制字变量,相应地修改了oct()函数。 2.X的方式如下: >>> 0666 438 >>> oct(438) '0666' 3.X这样: >>> 0666 SyntaxError: invalid token ( >>> 0o666 438 >>> oct(438) '0o666' 11)增加了 2进制字面量和bin()函数 >>> bin(438) '0b110110110' >>> _438 = '0b110110110' >>> _438 '0b110110110' 12)扩展的可迭代解包。在Py3.X 里,a, b, *rest = seq和 *rest, a = seq都是合法的,只要求两点:rest是list 对象和seq是可迭代的。 13)新的super(),可以不再给super()传参数, >>> class C(object): def __init__(self, a): print('C', a) >>> class D(C): def __init(self, a): super().__init__(a) # 无参数调用super() >>> D(8) C 8 <__main__.D object at 0x00D7ED90> 14)新的metaclass语法: class Foo(*bases, **kwds): pass 15)支持class decorator。用法与函数decorator一样: >>> def foo(cls_a): def print_func(self): print('Hello, world!') cls_ = print_func return cls_a >>> @foo class C(object): pass >>> C().print() Hello, world! class decorator可以用来玩玩狸猫换太子的大把戏。更多请参阅PEP 3129 4. 字符串和字节串 1)现在字符串只有str一种类型,但它跟2.x版本的unicode几乎一样。 2)关于字节串,请参阅“数据类型”的第2条目 5.数据类型 1)Py3.X去除了long类型,现在只有一种整型——int,但它的行为就像2.X版本的long 2)新增了bytes类型,对应于2.X版本的八位串,定义一个bytes字面量的方法如下: >>> b = b'china' >>> type(b) str对象和bytes对象可以使用.encode() (str -> bytes) or .decode() (bytes -> str)方法相互转化。 >>> s = () >>> s 'china' >>> b1 = () >>> b1 b'china' 3)dict的.keys()、.items 和.values()方法返回迭代器,而之前的iterkeys()等函数都被废弃。同时去掉的还有 _key(),用 in替代它吧 6.面向对象 1)引入抽象基类(Abstraact Base Classes,ABCs)。 2)容器类和迭代器类被ABCs化,所以cellections模块里的类型比Py2.5多了很多。 >>> import collections >>> print('n'.join(dir(collections))) Callable Container Hashable ItemsView Iterable Iterator KeysView Mapping MappingView MutableMapping MutableSequence MutableSet NamedTuple Sequence Set Sized ValuesView __all__ __builtins__ __doc__ __file__ __name__ _abcoll _itemgetter _sys defaultdict deque 另外,数值类型也被ABCs化。关于这两点,请参阅 PEP 3119和PEP 3141。 3)迭代器的next()方法改名为__next__(),并增加内置函数next(),用以调用迭代器的__next__()方法 4)增加了@abstractmethod和 @abstractproperty两个 decorator,编写抽象方法(属性)更加方便。 7.异常 1)所以异常都从 BaseException继承,并删除了StardardError 2)去除了异常类的序列行为和.message属性 3)用 raise Exception(args)代替 raise Exception, args语法 4)捕获异常的语法改变,引入了as关键字来标识异常实例,在Py2.5中: >>> try: ... raise NotImplementedError('Error') ... except NotImplementedError, error: ... print e ... Error 在Py3.0中: >>> try: raise NotImplementedError('Error') except NotImplementedError as error: #注意这个 as print(str(error)) Error 5)异常链,因为__context__在3.0a1版本中没有实现 8.模块变动 1)移除了cPickle模块,可以使用pickle模块代替。最终我们将会有一个透明高效的模块。 2)移除了imageop模块 3)移除了 audiodev, Bastion, bsddb185, exceptions, linuxaudiodev, md5, MimeWriter, mimify, popen2, rexec, sets, sha, stringold, strop, sunaudiodev, timing和xmllib模块 4)移除了bsddb模块(单独发布,可以从/programacion/获取) 5)移除了new模块 6)()和e()函数被移动到tmpfile模块下 7)tokenize模块现在使用bytes工作。主要的入口点不再是generate_tokens,而是 ze() 9.其它 1)xrange() 改名为range(),要想使用range()获得一个list,必须显式调用: >>> list(range(10)) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 2)bytes对象不能hash,也不支持 ()、()和()方法,但对于后两者可以使用 (b’ ntr f’)和(b’ ‘)来达到相同目的 3)zip()、map()和filter()都返回迭代器。而apply()、 callable()、coerce()、 execfile()、reduce()和reload ()函数都被去除了 现在可以使用hasattr()来替换 callable(). hasattr()的语法如:hasattr(string, '__name__') 4)s和相关的.lowercase和.uppercase被去除,请改用_letters 等 5)如果x < y的不能比较,抛出TypeError异常。2.x版本是返回伪随机布尔值的 6)__getslice__系列成员被废弃。a[i:j]根据上下文转换为a.__getitem__(slice(I, j))或 __setitem__和 __delitem__调用 7)file类被废弃,在Py2.5中: >>> file 在Py3.X中: >>> file Traceback (most recent call last): File " file NameError: name 'file' is not defined 使用 2to3 将代码移植到P YTHON 3 概述# 几乎所有的Python 2程序都需要一些修改才能正常地运行在Python 3的环境下。为了简化这个转换 过程,Python 3自带了一个叫做 2to3 的实用脚本(Utility Script),这个脚本会将你的Python 2程序源文 件作为输入,然后自动将其转换到Python 3的形式。案例研究:将 chardet 移植到Python 3(porting chardet to Python 3)描述了如何运行这个脚本,然后展示了一些它不能自动修复的情况。这篇附录描 述了它 能够 自动修复的内容。 print 语句 在Python 2里, print 是一个语句。无论你想输出什么,只要将它们放在 print 关键字后边就可以。 在Python 3里, print() 是一个函数。就像其他的函数一样, print() 需要你将想要输出的东西作为参 数传给它。 Notes Python 2 Python 3 ① ② ③ ④ ⑤ print print 1 print 1, 2 print 1, 2, print >>, 1, 2, 3 print() print(1) print(1, 2) print(1, 2, end=' ') print(1, 2, 3, file=) 1. 为输出一个空白行,需要调用不带参数的 print() 。 2. 为输出一个单独的值,需要将这这个值作为 print() 的一个参数就可以了。 3. 为输出使用一个空格分隔的两个值,用两个参数调用 print() 即可。 4. 这个例子有一些技巧。在Python 2里,如果你使用一个逗号(,)作为 print 语句的结尾,它将会用空 格分隔输出的结果,然后在输出一个尾随的空格(trailing space),而不输出回车(carriage return)。在 Python 3里,通过把 end=' ' 作为一个关键字参数传给 print() 可以实现同样的效果。参数 end 的默 认值为 'n' ,所以通过重新指定 end 参数的值,可以取消在末尾输出回车符。 5. 在Python 2里,你可以通过使用 >>pipe_name 语法,把输出重定向到一个管道,比如 。 在Python 3里,你可以通过将管道作为关键字参数 file 的值传递给 print() 来完成同样的功能。 参数 file 的默认值为 ,所以重新指定它的值将会使 print() 输出到一个另外一个管道。 U NICODE 字符串# Python 2有两种字符串类型:Unicode字符串和非Unicode字符串。Python 3只有一种类型:Unicode 字符串(Unicode strings)。 Notes Python 2 Python 3 ① ② u'PapayaWhip' ur'PapayaWhipfoo' 'PapayaWhip' r'PapayaWhipfoo' 1. Python 2里的Unicode字符串在Python 3里即普通字符串,因为在Python 3里字符串总是Unicode 形式的。 2. Unicode原始字符串(raw string)(使用这种字符串,Python不会自动转义反斜线"")也被替换为普通 的字符串,因为在Python 3里,所有原始字符串都是以Unicode编码的。 全局函数 unicode() # Python 2有两个全局函数可以把对象强制转换成字符串: unicode() 把对象转换成Unicode字符串,还 有 str() 把对象转换为非Unicode字符串。Python 3只有一种字符串类型,Unicode字符串,所以 str() 函数即可完成所有的功能。( unicode() 函数在Python 3里不再存在了。) Notes Python 2 Python 3 long 长整型# unicode(anything) str(anything) Python 2有为非浮点数准备的 int 和 long 类型。 int 类型的最大值不能超过 ,而且这个最 大值是平台相关的。可以通过在数字的末尾附上一个 L 来定义长整型,显然,它比 int 类型表示的数 字范围更大。在Python 3里,只有一种整数类型 int ,大多数情况下,它很像Python 2里的长整型。 由于已经不存在两种类型的整数,所以就没有必要使用特殊的语法去区别他们。 进一步阅读:pep 237:统一长整型和整型。 Notes Python 2 Python 3 ① ② ③ x = 1L x = 0xFFFFFFFFFFFFL long(x) x = 1 x = 0xFFFFFFFFFFFF int(x) ④ ⑤ type(x) is long isinstance(x, long) type(x) is int isinstance(x, int) 1. 在Python 2里的十进制长整型在Python 3里被替换为十进制的普通整数。 2. 在Python 2里的十六进制长整型在Python 3里被替换为十六进制的普通整数。 3. 在Python 3里,由于长整型已经不存在了,自然原来的 long() 函数也没有了。为了强制转换一个 变量到整型,可以使用 int() 函数。 4. 检查一个变量是否是整型,获得它的数据类型,并与一个 int 类型(不是 long )的作比较。 5. 你也可以使用 isinstance() 函数来检查数据类型;再强调一次,使用 int ,而不是 long ,来检查整 数类型。 <> 比较运算符# Python 2支持 <> 作为 != 的同义词。Python 3只支持 != ,不再支持<>了。 Notes Python 2 Python 3 ① ② if x <> y: if x <> y <> z: if x != y: if x != y != z: 1. 简单地比较。 2. 相对复杂的三个值之间的比较。 字典类方法 has_key() # 在Python 2里,字典对象的 has_key() 方法用来测试字典是否包含特定的键(key)。Python 3不再支持 这个方法了。你需要使用 in 运算符。 Note s Python 2 Python 3 ① ② ③ a__key('PapayaWhip') a__key(x) or a__key(y ) a__key(x or y) 'PapayaWhip' in a_dictionary x in a_dictionary or y in a_dictionar y (x or y) in a_dictionary ④ ⑤ a__key(x + y) x + a__key(y) (x + y) in a_dictionary x + (y in a_dictionary) 1. 最简单的形式。 2. 运算符 or 的优先级高于运算符 in ,所以这里不需要添加括号。 3. 另一方面,出于同样的原因 — or 的优先级大于 in ,这里需要添加括号。(注意:这里的代码与前 面那行完全不同。Python会先解释 x or y ,得到结果 x (如果 x 在布尔上下文里的值是真)或者 y 。 然后Python检查这个结果是不是 a_dictionary 的一个键。) 4. 运算符 in 的优先级大于运算符 + ,所以代码里的这种形式从技术上说不需要括号,但是 2to3 还是 添加了。 5. 这种形式一定需要括号,因为 in 的优先级大于 + 。 返回列表的字典类方法# 在Python 2里,许多字典类方法的返回值是列表。其中最常用方法的有 keys , items 和 values 。在Python 3里,所有以上方法的返回值改为动态视图(dynamic view)。在一些上下文环境里,这种改变并不会产 生影响。如果这些方法的返回值被立即传递给另外一个函数,并且那个函数会遍历整个序列,那么以 上方法的返回值是列表或者视图并不会产生什么不同。在另外一些情况下,Python 3的这些改变干系 重大。如果你期待一个能被独立寻址元素的列表,那么Python 3的这些改变将会使你的代码卡住 (choke),因为视图(view)不支持索引(indexing)。 Notes Python 2 Python 3 ① ② ③ ④ ⑤ a_() a_() a_ys() [i for i in a_ys()] min(a_()) list(a_()) list(a_()) iter(a_()) [i for i in a_()] no change 1. 使用 list() 函数将 keys() 的返回值转换为一个静态列表,出于安全方面的考量, 2to3 可能会报错。 这样的代码是有效的,但是对于使用视图来说,它的效率低一些。你应该检查转换后的代码,看 看是否一定需要列表,也许视图也能完成同样的工作。 2. 这是另外一种视图(关于 items() 方法的)到列表的转换。 2to3 对 values() 方法返回值的转换也是一 样的。 3. Python 3里不再支持 iterkeys() 了。如果必要,使用 iter() 将 keys() 的返回值转换成为一个迭代器。 4. 2to3 能够识别出 iterkeys() 方法在列表解析里被使用,然后将它转换为Python 3里的 keys() 方法(不 需要使用额外的 iter() 去包装其返回值)。这样是可行的,因为视图是可迭代的。 5. 2to3 也能识别出 keys() 方法的返回值被立即传给另外一个会遍历整个序列的函数,所以也就没有 必要先把 keys() 的返回值转换到一个列表。相反的, min() 函数会很乐意遍历视图。这个过程对 min() , max() , sum() , list() , tuple() , set() , sorted() , any() 和 all() 同样有效。 被重命名或者重新组织的模块 从Python 2到Python 3,标准库里的一些模块已经被重命名了。还有一些相互关联的模块也被组合或 者重新组织,以使得这种关联更有逻辑性。 http 在Python 3里,几个相关的http模块被组合成一个单独的包,即 http 。 Notes Python 2 Python 3 ① ② ③ import httplib import Cookie import cookielib import import s import jar import import BaseHTTPServer import SimpleHTTPServer ④ import CGIHttpServer 1. 模块实现了一个底层的库,可以用来请求http资源,解析http响应。 2. s 模块提供一个蟒样的(Pythonic)接口来获取通过http头部(http header)Set-Cookie发送 的cookies 3. 常用的流行的浏览器会把cookies以文件形式存放在磁盘上, jar 模块可以操作这些文 件。 4. 模块实现了一个基本的http服务器 urllib # Python 2有一些用来分析,编码和获取URL的模块,但是这些模块就像老鼠窝一样相互重叠。在Python 3里,这些模块被重构、组合成了一个单独的包,即 urllib 。 Notes Python 2 Python 3 ① ② ③ ④ import urllib import urllib2 import urlparse import robotparser import t, , import t, import import arser from urllib import FancyURLopener from urllib import ⑤ urlencode from urllib2 import Request from urllib2 import ⑥ HTTPError from t import FancyURLopener from import urlencode from t import Request from import HTTPError 1. 以前,Python 2里的 urllib 模块有各种各样的函数,包括用来获取数据的 urlopen() ,还有用来将 url分割成其组成部分的 splittype() , splithost() 和 splituser() 函数。在新的 urllib 包里,这些 函数被组织得更有逻辑性。2to3将会修改这些函数的调用以适应新的命名方案。 2. 在Python 3里,以前的 urllib2 模块被并入了 urllib 包。同时,以 urllib2 里各种你最喜爱的东西 将会一个不缺地出现在Python 3的 urllib 模块里,比如 build_opener() 方法, Request 对象, HTTPBasicAuthHandler 和friends。 3. Python 3里的 模块包含了原来Python 2里 urlparse 模块所有的解析函数。 4. arse 模块解析 文件。 5. 处理http重定向和其他状态码的 FancyURLopener 类在Python 3里的 t 模块里依然有 效。 urlencode() 函数已经被转移到了 里。 6. Request 对象在 t 里依然有效,但是像 HTTPError 这样的常量已经被转移到了 里。 我是否有提到 2to3 也会重写你的函数调用?比如,如果你的Python 2代码里导入了 urllib 模块,调 用了 n() 函数获取数据, 2to3 会同时修改 import 语句和函数调用。 No tes Python 2 Python 3 import urllib print n('diveintop dbm # /').read() import t, , print(n('dive /').read()) 所有的dbm克隆(dbm clone)现在在单独的一个包里,即 dbm 。如果你需要其中某个特定的变体,比如 gnu dbm,你可以导入 dbm 包中合适的模块。 Notes Python 2 Python 3 import dbm import gdbm import dbhash import dumbdbm import import import import import dbm import anydbm xmlrpc # import whichdb xml-rpc是一个通过http协议执行远程rpc调用的轻重级方法。一些xml-rpc客户端和xml-rpc服务端 的实现库现在被组合到了独立的包,即 xmlrpc 。 Notes Python 2 Python 3 import xmlrpclib import import import DocXMLRPCServer import SimpleXMLRPCServer 其他模块# Notes Python 2 Python 3 try: import cStringIO as StringIO except ImportError: ① import StringIO try: import cPickle as pickle except ImportError: ② ③ ④ ⑤ ⑥ ⑦ ⑧ ⑨ import pickle import __builtin__ import copy_reg import Queue import SocketServer import ConfigParser import repr import commands import io import pickle import builtins import copyreg import queue import socketserver import configparser import reprlib import subprocess 1. 在Python 2里,你通常会这样做,首先尝试把 cStringIO 导入作为 StringIO 的替代,如果失败了, 再导入 StringIO 。不要在Python 3里这样做; io 模块会帮你处理好这件事情。它会找出可用的最 快实现方法,然后自动使用它。 2. 在Python 2里,导入最快的 pickle 实现也是一个与上边相似的能用方法。在Python 3里, pickle 模块会自动为你处理,所以不要再这样做。 3. builtins 模块包含了在整个Python语言里都会使用的全局函数,类和常量。重新定义 builtins 模 块里的某个函数意味着在每处都重定义了这个全局函数。这听起来很强大,但是同时也是很可怕 的。 4. copyreg 模块为用C语言定义的用户自定义类型添加了 pickle 模块的支持。 5. queue 模块实现一个生产者消费者队列(multi-producer, multi-consumer queue)。 6. socketserver 模块为实现各种socket server提供了通用基础类。 7. configparser 模块用来解析ini-style配置文件。 8. reprlib 模块重新实现了内置函数 repr() ,并添加了对字符串表示被截断前长度的控制。 9. subprocess 模块允许你创建子进程,连接到他们的管道,然后获取他们的返回值。 包内的相对导入 包是由一组相关联的模块共同组成的单个实体。在Python 2的时候,为了实现同一个包内模块的相 互引用,你会使用 import foo 或者 from foo import Bar 。Python 2解释器会先在当前目录里搜索 , 然后再去Python搜索路径( )里搜索。在Python 3里这个过程有一点不同。Python 3不会首先 在当前路径搜索,它会直接在Python的搜索路径里寻找。如果你想要包里的一个模块导入包里的另 外一个模块,你需要显式地提供两个模块的相对路径。 假设你有如下包,多个文件在同一个目录下: chardet/ | +--__init__.py | +-- | +-- | +-- 现在假设 需要整个导入 ,另外还需要导入 的一 个类。你会怎样做? Note s Python 2 Python 3 ① import constants from mbcharsetprober import MultiByteCharSe tProber from . import constants from .mbcharsetprober import MultiByteCharse tProber ② 1. 当你需要从包的其他地方导入整个模块,使用新的 from . import 语法。这里的句号(.)即表示当前 文件( )和你想要导入文件( )之间的相对路径。在这个样例中,这 两个文件在同一个目录里,所以使用了单个句号。你也可以从父目录( from .. import anothermodule ) 或者子目录里导入。 2. 为了将一个特定的类或者函数从其他模块里直接导入到你的模块的名字空间里,在需要导入的模 块名前加上相对路径,并且去掉最后一个斜线(slash)。在这个例子中, 与 在同一个目录里,所以相对路径名就是一个句号。你也可以从父目录(from .. import anothermodule)或者子目录里导入。 迭代器方法 next() # 在Python 2里,迭代器有一个 next() 方法,用来返回序列里的下一项。在Python 3里这同样成立, 但是现在有了一个新的全局的函数 next() ,它使用一个迭代器作为参数。 Note s Python 2 Python 3 ① ② () a_function_that_returns_an_iterator().next( ) next(anIterator) next(a_function_that_returns_an_iterator() ) class A: def next(self): ③ pass class A: def next(self, x, y): ④ pass next = 42 ⑤ for an_iterator in class A: def __next__(self): pass no change next = 42 for an_iterator in a_sequence_of_iterators: an_() a_sequence_of_iterators: an_iterator.__next__() 1. 最简单的例子,你不再调用一个迭代器的 next() 方法,现在你将迭代器自身作为参数传递给全局 函数 next() 。 2. 假如你有一个返回值是迭代器的函数,调用这个函数然后把结果作为参数传递给 next() 函数。( 2to3 脚本足够智能以正确执行这种转换。) 3. 假如你想定义你自己的类,然后把它用作一个迭代器,在Python 3里,你可以通过定义特殊方法 __next__() 来实现。 4. 如果你定义的类里刚好有一个 next() ,它使用一个或者多个参数, 2to3 执行的时候不会动它。这 个类不能被当作迭代器使用,因为它的 next() 方法带有参数。 5. 这一个有些复杂。如果你恰好有一个叫做 next 的本地变量,在Python 3里它的优先级会高于全局 函数 next() 。在这种情况下,你需要调用迭代器的特别方法 __next__() 来获取序列里的下一个元素。 (或者,你也可以重构代码以使这个本地变量的名字不叫 next ,但是2to3不会为你做这件事。) 全局函数 filter() # 在Python 2里, filter() 方法返回一个列表,这个列表是通过一个返回值为 True 或者 False 的函数来 检测序列里的每一项得到的。在Python 3里, filter() 函数返回一个迭代器,不再是列表。 Notes Python 2 Python 3 ① ② ③ ④ ⑤ filter(a_function, a_sequence) list(filter(a_function, a_sequence)) filter(None, a_sequence) for i in filter(None, a_sequence): [i for i in filter(a_function, a_sequence)] list(filter(a_function, a_sequence)) no change [i for i in a_sequence if i] no change no change 1. 最简单的情况下, 2to3 会用一个 list() 函数来包装 filter() , list() 函数会遍历它的参数然后返回 一个列表。 2. 然而,如果 filter() 调用已经被 list() 包裹, 2to3 不会再做处理,因为这种情况下 filter() 的返 回值是否是一个迭代器是无关紧要的。 3. 为了处理 filter(None, ...) 这种特殊的语法, 2to3 会将这种调用从语法上等价地转换为列表解析。 4. 由于 for 循环会遍历整个序列,所以没有必要再做修改。 5. 与上面相同,不需要做修改,因为列表解析会遍历整个序列,即使 filter() 返回一个迭代器,它 仍能像以前的 filter() 返回列表那样正常工作。 全局函数 map() 跟 filter() 作的改变一样, map() 函数现在返回一个迭代器。(在Python 2里,它返回一个列表。) Notes Python 2 Python 3 ① ② ③ ④ ⑤ map(a_function, 'PapayaWhip') map(None, 'PapayaWhip') map(lambda x: x+1, range(42)) for i in map(a_function, a_sequence): [i for i in map(a_function, a_sequence)] list(map(a_function, 'PapayaWhip')) list('PapayaWhip') [x+1 for x in range(42)] no change no change 1. 类似对 filter() 的处理,在最简单的情况下, 2to3 会用一个 list() 函数来包装 map() 调用。 2. 对于特殊的 map(None, ...) 语法,跟 filter(None, ...) 类似, 2to3 会将其转换成一个使用 list() 的等价调用 3. 如果 map() 的第一个参数是一个lambda函数, 2to3 会将其等价地转换成列表解析。 4. 对于会遍历整个序列的 for 循环,不需要做改变。 5. 再一次地,这里不需要做修改,因为列表解析会遍历整个序列,即使 map() 的返回值是迭代器而不 是列表它也能正常工作。 全局函数 reduce() # 在Python 3里, reduce() 函数已经被从全局名字空间里移除了,它现在被放置在 fucntools 模块里。 Notes Python 2 Python 3 reduce(a, b, c) from functools import reduce reduce(a, b, c) 全局函数 apply() # Python 2有一个叫做 apply() 的全局函数,它使用一个函数 f 和一个列表 [a, b, c] 作为参数,返回值 是 f(a, b, c) 。你也可以通过直接调用这个函数,在列表前添加一个星号(*)作为参数传递给它来完成 同样的事情。在Python 3里, apply() 函数不再存在了;必须使用星号标记法。 Not es Python 2 Python 3 ① ② ③ ④ apply(a_function, a_list_of_args) apply(a_function, a_list_of_args, a_dictionar y_of_named_args) apply(a_function, a_list_of_args + z) apply(aModule.a_function, a_list_of_args) a_function(*a_list_of_args) a_function(*a_list_of_args, **a_dictionary _of_named_args) a_function(*a_list_of_args + z) aModule.a_function(*a_list_of_args) 1. 最简单的形式,可以通过在参数列表(就像 [a, b, c] 一样)前添加一个星号来调用函数。这跟Python 2里的 apply() 函数是等价的。 2. 在Python 2里, apply() 函数实际上可以带3个参数:一个函数,一个参数列表,一个字典命名参 数(dictionary of named arguments)。在Python 3里,你可以通过在参数列表前添加一个星号( * ),在 字典命名参数前添加两个星号( ** )来达到同样的效果。 3. 运算符 + 在这里用作连接列表的功能,它的优先级高于运算符 * ,所以没有必要在 a_list_of_args + z 周围添加额外的括号。 4. 2to3 脚本足够智能来转换复杂的 apply() 调用,包括调用导入模块里的函数。 全局函数 intern() # 在Python 2里,你可以用 intern() 函数作用在一个字符串上来限定(intern)它以达到性能优化。在 Python 3里, intern() 函数被转移到 sys 模块里了。 Notes Python 2 Python 3 exec 语句# intern(aString) (aString) 就像 print 语句在Python 3里变成了一个函数一样, exec 语句也是这样的。 exec() 函数使用一个包含 任意Python代码的字符串作为参数,然后就像执行语句或者表达式一样执行它。 exec() 跟 eval() 是 相似的,但是 exec() 更加强大并更具有技巧性。 eval() 函数只能执行单独一条表达式,但是exec () 能够执行多条语句,导入(import),函数声明 — 实际上整个Python程序的字符串表示也可以。 Not es Python 2 Python 3 ① ② ③ exec codeString exec codeString in a_global_namespace exec codeString in a_global_namespace, a_loc al_namespace exec(codeString) exec(codeString, a_global_namespace) exec(codeString, a_global_namespace, a_loca l_namespace) 1. 在最简单的形式下,因为 exec() 现在是一个函数,而不是语句, 2to3 会把这个字符串形式的代码 用括号围起来。 2. Python 2里的 exec 语句可以指定名字空间,代码将在这个由全局对象组成的私有空间里执行。 Python 3也有这样的功能;你只需要把这个名字空间作为第二个参数传递给 exec() 函数。 3. 更加神奇的是,Python 2里的 exec 语句还可以指定一个本地名字空间(比如一个函数里声明的变量)。 在Python 3里, exec() 函数也有这样的功能。 execfile 语句# 就像以前的 exec 语句,Python 2里的 execfile 语句也可以像执行Python代码那样使用字符串。不同 的是 exec 使用字符串,而 execfile 则使用文件。在Python 3里, execfile 语句已经被去掉了。如果 你真的想要执行一个文件里的Python代码(但是你不想导入它),你可以通过打开这个文件,读取它的 内容,然后调用 compile() 全局函数强制Python解释器编译代码,然后调用新的 exec() 函数。 Notes Python 2 Python 3 execfile('a_filename') exec(compile(open('a_filename').read(), 'a_filename', 'exec')) repr (反引号)# 在Python 2里,为了得到一个任意对象的字符串表示,有一种把对象包装在反引号里(比如 `x` )的特殊 语法。在Python 3里,这种能力仍然存在,但是你不能再使用反引号获得这种字符串表示了。你需 要使用全局函数 repr() 。 Notes Python 2 Python 3 ① ② `x` `'PapayaWhip' + `2`` repr(x) repr('PapayaWhip' + repr(2)) 1. 记住, x 可以是任何东西 — 一个类,函数,模块,基本数据类型,等等。 repr() 函数可以使用任何 类型的参数。 2. 在Python 2里,反引号可以嵌套,导致了这种令人费解的(但是有效的)表达式。 2to3 足够智能以将 这种嵌套调用转换到 repr() 函数。 pt 语句 从Python 2到Python 3,捕获异常的语法有些许变化。 Notes Python 2 Python 3 try: import mymodule except ImportError, e ① pass try: import mymodule except (RuntimeError, ImportError), e ② pass try: import mymodule except ImportError: ③ pass try: import mymodule except: ④ pass try: import mymodule except ImportError as e: pass try: import mymodule except (RuntimeError, ImportError) as e: pass no change no change 1. 相对于Python 2里在异常类型后添加逗号,Python 3使用了一个新的关键字, as 。 2. 关键字 as 也可以用在一次捕获多种类型异常的情况下。 3. 如果你捕获到一个异常,但是并不在意访问异常对象本身,Python 2和Python 3的语法是一样的。 4. 类似地,如果你使用一个保险方法(fallback)来捕获 所有 异常,Python 2和Python 3的语法是一样的。 ☞ 在导入模块(或者其他大多数情况)的时候,你绝对不应该使用这种方法(指以上的fallback)。不然 的话,程序可能会捕获到像 KeyboardInterrupt (如果用户按 Ctrl-C 来中断程序)这样的异常,从而使调 试变得更加困难。 raise 语句 Python 3里,抛出自定义异常的语法有细微的变化。 Notes Python 2 Python 3 ① ② raise MyException raise MyException, 'error message' raise MyException, 'error message', a_traceback raise 'error message' unchanged raise MyException('error message') raise MyException('error message').with_traceback(a_traceback) unsupported ③ ④ 1. 抛出不带用户自定义错误信息的异常,这种最简单的形式下,语法没有改变。 2. 当你想要抛出一个带用户自定义错误信息的异常时,改变就显而易见了。Python 2用一个逗号来 分隔异常类和错误信息;Python 3把错误信息作为参数传递给异常类。 3. Python 2支持一种更加复杂的语法来抛出一个带用户自定义回溯(stack trace,堆栈追踪)的异常。 在Python 3里你也可以这样做,但是语法完全不同。 4. 在Python 2里,你可以抛出一个不带异常类的异常,仅仅只有一个异常信息。在Python 3里,这 种形式不再被支持。 2to3 将会警告你它不能自动修复这种语法。 生成器的 throw 方法# 在Python 2里,生成器有一个 throw() 方法。调用 a_() 会在生成器被暂停的时候抛出 一个异常,然后返回由生成器函数获取的下一个值。在Python 3里,这种功能仍然可用,但是语法 上有一点不同。 Notes Python 2 Python 3 no change ① ② ③ a_(MyException) a_(MyException, 'error message') a_('error message') a_(MyException('error message')) unsupported 1. 最简单的形式下,生成器抛出不带用户自定义错误信息的异常。这种情况下,从Python 2到Python 3语法上没有变化 。 2. 如果生成器抛出一个带用户自定义错误信息的异常,你需要将这个错误信息字符串(error string)传 递给异常类来以实例化它。 3. Python 2还支持抛出只有异常信息的异常。Python 3不支持这种语法,并且 2to3 会显示一个警告 信息,告诉你需要手动地来修复这处代码。 全局函数 xrange() # 在Python 2里,有两种方法来获得一定范围内的数字: range() ,它返回一个列表,还有 range() ,它 返回一个迭代器。在Python 3里, range() 返回迭代器, xrange() 不再存在了。 Notes Python 2 Python 3 ① ② ③ ④ ⑤ xrange(10) a_list = range(10) [i for i in xrange(10)] for i in range(10): sum(range(10)) range(10) a_list = list(range(10)) [i for i in range(10)] no change no change 1. 在最简单的情况下, 2to3 会简单地把 xrange() 转换为 range() 。 2. 如果你的Python 2代码使用 range() , 2to3 不知道你是否需要一个列表,或者是否一个迭代器也行。 出于谨慎, 2to3 可能会报错,然后使用 list() 把 range() 的返回值强制转换为列表类型。 3. 如果在列表解析里有 xrange() 函数,就没有必要将其返回值转换为一个列表,因为列表解析对迭 代器同样有效。 4. 类似的, for 循环也能作用于迭代器,所以这里也没有改变任何东西。 5. 函数 sum() 能作用于迭代器,所以 2to3 也没有在这里做出修改。就像返回值为视图(view)而不再是 列表的字典类方法一样,这同样适用于 min() , max() , sum() ,list(), tuple() , set() , sorted() , any() , all() 。 全局函数 raw_input() 和 input() Python 2有两个全局函数,用来在命令行请求用户输入。第一个叫做 input() ,它等待用户输入一个 Python表达式(然后返回结果)。第二个叫做 raw_input() ,用户输入什么它就返回什么。这让初学者非 常困惑,并且这被广泛地看作是Python语言的一个“肉赘”(wart)。Python 3通过重命名 raw_input() 为 input() ,从而切掉了这个肉赘,所以现在的 input() 就像每个人最初期待的那样工作。 Notes Python 2 Python 3 ① ② ③ raw_input() raw_input('prompt') input() input() input('prompt') eval(input()) 1. 最简单的形式, raw_input() 被替换成 input() 。 2. 在Python 2里, raw_input() 函数可以指定一个提示符作为参数。Python 3里保留了这个功能。 3. 如果你真的想要请求用户输入一个Python表达式,计算结果,可以通过调用 input() 函数然后把返 回值传递给 eval() 。 函数属性 func_* # 在Python 2里,函数的里的代码可以访问到函数本身的特殊属性。在Python 3里,为了一致性,这 些特殊属性被重新命名了。 Notes Python 2 Python 3 ① ② ③ ④ ⑤ a__name a__doc a__defaults a__dict a__closure a_function.__name__ a_function.__doc__ a_function.__defaults__ a_function.__dict__ a_function.__closure__ ⑥ ⑦ a__globals a__code a_function.__globals__ a_function.__code__ 1. __name__ 属性(原 func_name )包含了函数的名字。 2. __doc__ 属性(原 funcdoc )包含了你在函数源代码里定义的文档字符串(docstring) 3. __defaults__ 属性(原 func_defaults )是一个保存参数默认值的元组。 4. __dict__ 属性(原 func_dict )是一个支持任意函数属性的名字空间。 5. __closure__ 属性(原 func_closure )是一个由cell对象组成的元组,它包含了函数对自由变量(free variable)的绑定。 6. __globals__ 属性(原 func_globals )是一个对模块全局名字空间的引用,函数本身在这个名字空间里 被定义。 7. __code__ 属性(原 func_code )是一个代码对象,表示编译后的函数体。 I/O方法 xreadlines() # 在Python 2里,文件对象有一个 xreadlines() 方法,它返回一个迭代器,一次读取文件的一行。这在 for 循环中尤其有用。事实上,后来的Python 2版本给文件对象本身添加了这样的功能。 在Python 3里, xreadlines() 方法不再可用了。 2to3 可以解决简单的情况,但是一些边缘案例则需要 人工介入。 Notes Python 2 Python 3 ① ② for line in a_ines(): for line in a_ines(5): for line in a_file: no change (broken) 1. 如果你以前调用没有参数的 xreadlines() , 2to3 会把它转换成文件对象本身。在Python 3里,这 种转换后的代码可以完成前同样的工作:一次读取文件的一行,然后执行 for 循环的循环体。 2. 如果你以前使用一个参数(每次读取的行数)调用 xreadlines() , 2to3 不能为你完成从Python 2到 Python 3的转换,你的代码会以这样的方式失败: AttributeError: '_Wrapper' object has no attribute 'xreadlines' 。你可以手工的把 xreadlines() 改成 readlines() 以使代码能在Python 3 下工作。(readline()方法在Python 3里返回迭代器,所以它跟Python 2里的 xreadlines() 效率是不 相上下的。) ☃ 使用元组而非多个参数的 lambda 函数 在Python 2里,你可以定义匿名 lambda 函数(anonymous lambda function),通过指定作为参数的元组 的元素个数,使这个函数实际上能够接收多个参数。事实上,Python 2的解释器把这个元组“解 开”(unpack)成命名参数(named arguments),然后你可以在 lambda 函数里引用它们(通过名字)。在Python 3里,你仍然可以传递一个元组作为 lambda 函数的参数,但是Python解释器不会把它解析成命名参 数。你需要通过位置索引(positional index)来引用每个参数。 Notes Python 2 Python 3 ① ② ③ ④ lambda (x,): x + f(x) lambda (x, y): x + f(y) lambda (x, (y, z)): x + y + z lambda x, y, z: x + y + z lambda x1: x1[0] + f(x1[0]) lambda x_y: x_y[0] + f(x_y[1]) lambda x_y_z: x_y_z[0] + x_y_z[1][0] + x_y_z[1][1] unchanged 1. 如果你已经定义了一个 lambda 函数,它使用包含一个元素的元组作为参数,在Python 3里,它会 被转换成一个包含到 x1[0] 的引用的 lambda 函数。 x1 是 2to3 脚本基于原来元组里的命名参数自动 生成的。 2. 使用含有两个元素的元组 (x, y) 作为参数的 lambda 函数被转换为 x_y ,它有两个位置参数,即 x_y[0] 和 x_y[1] 。 3. 2to3 脚本甚至可以处理使用嵌套命名参数的元组作为参数的 lambda 函数。产生的结果代码有点难 以阅读,但是它在Python 3下跟原来的代码在Python 2下的效果是一样的。 4. 你可以定义使用多个参数的 lambda 函数。如果没有括号包围在参数周围,Python 2会把它当作一 个包含多个参数的 lambda 函数;在这个 lambda 函数体里,你通过名字引用这些参数,就像在其他 类型的函数里所做的一样。这种语法在Python 3里仍然有效。 特殊的方法属性# 在Python 2里,类方法可以访问到定义他们的类对象(class object),也能访问方法对象(method object) 本身。 im_self 是类的实例对象; im_func 是函数对象, im_class 是类本身。在Python 3里,这些属性 被重新命名,以遵循其他属性的命名约定。 Notes Python 2 Python 3 _func _self _class Method.__func__ Method.__self__ Method.__self__.__class__ __nonzero__ 特殊方法# 在Python 2里,你可以创建自己的类,并使他们能够在布尔上下文(boolean context)中使用。举例来 说,你可以实例化这个类,并把这个实例对象用在一个 if 语句中。为了实现这个目的,你定义一个 特别的 __nonzero__() 方法,它的返回值为 True 或者 False ,当实例对象处在布尔上下文中的时候这个 方法就会被调用 。在Python 3里,你仍然可以完成同样的功能,但是这个特殊方法的名字变成了 __bool__() 。 Notes Python 2 Python 3 class A: def __nonzero__(self): ① pass class A: def __nonzero__(self, x, y): ② pass class A: def __bool__(self): pass no change 1. 当在布尔上下文使用一个类对象时,Python 3会调用 __bool__() ,而非 __nonzero__() 。 2. 然而,如果你有定义了一个使用两个参数的 __nonzero__() 方法, 2to3 脚本会假设你定义的这个方 法有其他用处,因此不会对代码做修改。 八进制类型# 在Python 2和Python 3之间,定义八进制(octal)数的语法有轻微的改变。 Notes Python 2 Python 3 x = 0755 x = 0o755 由于长整型和整型被整合在一起了, 常量不再精确。但是因为这个值对于检测特定平台的 能力还是有用处的,所以它被Python 3保留,并且重命名为 e 。 Notes Python 2 Python 3 ① ② from sys import maxint a_function() from sys import maxsize a_function(e) 1. maxint 变成了 maxsize 。 2. 所有的 都变成了 e 。 全局函数 callable() # 在Python 2里,你可以使用全局函数 callable() 来检查一个对象是否可调用(callable,比如函数)。在 Python 3里,这个全局函数被取消了。为了检查一个对象是否可调用,可以检查特殊方法 __call__() 的存在性。 Notes Python 2 Python 3 callable(anything) hasattr(anything, '__call__') 全局函数 zip() # 在Python 2里,全局函数 zip() 可以使用任意多个序列作为参数,它返回一个由元组构成的列表。第 一个元组包含了每个序列的第一个元素;第二个元组包含了每个序列的第二个元素;依次递推下去。 在Python 3里, zip() 返回一个迭代器,而非列表。 Notes Python 2 Python 3 ① ② zip(a, b, c) (zip(a, b, c)) list(zip(a, b, c)) no change 1. 最简单的形式,你可以通过调用 list() 函数包装 zip() 的返回值来恢复 zip() 函数以前的功能, list() 函数会遍历这个 zip() 函数返回的迭代器,然后返回结果的列表表示。 2. 在已经会遍历序列所有元素的上下文环境里(比如这里对 join() 方法的调用), zip() 返回的迭代器 能够正常工作。 2to3 脚本会检测到这些情况,不会对你的代码作出改变。 StandardError 异常 在Python 2里, StandardError 是除了 StopIteration , GeneratorExit , KeyboardInterrupt , SystemExit 之外所有其他内置异常的基类。在Python 3里, StandardError 已经被取消了;使用 Exception 替代。 Notes Python 2 Python 3 x = StandardError() x = StandardError(a, b, c) x = Exception() x = Exception(a, b, c) types 模块中的常量# types 模块里各种各样的常量能帮助你决定一个对象的类型。在Python 2里,它包含了代表所有基本 数据类型的常量,如 dict 和 int 。在Python 3里,这些常量被已经取消了。只需要使用基础类型的名 字来替代。 Notes Python 2 Python 3 eType Type pe e pe pe pe nType Type ype xType str bytes dict int int list type(None) bool memoryview type complex isType ype Type lementedType ype ype pe Type type(Ellipsis) float object type(NotImplemented) slice tuple type range ☞ Type 被映射为 bytes ,而非 str ,因为Python 2里的“string”(非Unicode编码的字符串, 即普通字符串)事实上只是一些使用某种字符编码的字节序列(a sequence of bytes)。 全局函数 isinstance() # isinstance() 函数检查一个对象是否是一个特定类(class)或者类型(type)的实例。在Python 2里,你可 以传递一个由类型(types)构成的元组给 isinstance() ,如果该对象是元组里的任意一种类型,函数返 回 True 。在Python 3里,你依然可以这样做,但是不推荐使用把一种类型作为参数传递两次。 Notes Python 2 Python 3 isinstance(x, (int, float, int)) isinstance(x, (int, float)) basestring 数据类型# Python 2有两种字符串类型:Unicode编码的字符串和非Unicode编码的字符串。但是其实还有另外 一 种类型,即 basestring 。它是一个抽象数据类型,是 str 和 unicode 类型的超类(superclass)。它不能 被直接调用或者实例化,但是你可以把它作为 isinstance() 的参数来检测一个对象是否是一个 Unicode字符串或者非Unicode字符串。在Python 3里,只有一种字符串类型,所以 basestring 就没 有必要再存在了。 Notes Python 2 Python 3 isinstance(x, basestring) isinstance(x, str) itertools 模块 Python 2.3引入了 itertools 模块,它定义了全局函数 zip() , map() , filter() 的变体(variant),这些 变体的返回类型为迭代器,而非列表。在Python 3里,由于这些全局函数的返回类型本来就是迭代 器,所以这些 itertools 里的这些变体函数就被取消了。(在 itertools 模块里仍然还有许多其他的有 用的函数,而不仅仅是以上列出的这些。) Notes Python 2 Python 3 ① ② ③ ④ (a, b) (a, b) r(a, b) from itertools import imap, izip, foo zip(a, b) map(a, b) filter(a, b) from itertools import foo 1. 使用全局的 zip() 函数,而非 () 。 2. 使用 map() 而非 () 。 3. r() 变成了 filter() 。 4. itertools 模块在Python 3里仍然存在,它只是不再包含那些已经转移到全局名字空间的函数。 2to3 脚本能够足够智能地去移除那些不再有用的导入语句,同时保持其他的导入语句的完整性。 _type , _value , _traceback # 处理异常的时候,在 sys 模块里有三个你可以访问的变量: _type, _value, _traceback。(实际上这些在Python 1的时代就有。)从Python 1.5开始,由于新出的 _info,不再推荐使用这三个变量了,这是一个包含所有以上三个元素的元组。在Python 3 里,这三个变量终于不再存在了;这意味着,你必须使用_info。 Notes Python 2 Python 3 _type _value _traceback _info()[0] _info()[1] _info()[2] 对元组的列表解析# 在Python 2里,如果你需要编写一个遍历元组的列表解析,你不需要在元组值的周围加上括号。在 Python 3里,这些括号是必需的。 Notes Python 2 Python 3 u() 函数# [i for i in 1, 2] [i for i in (1, 2)] Python 2有一个叫做 () 的函数,它将当前的工作目录作为一个(非Unicode编码的)字符串 返回。由于现代的文件系统能够处理能何字符编码的目录名,Python 2.3引入了 u() 函数。 u() 函数把当前工作目录用Unicode编码的字符串返回。在Python 3里,由于只有一种字 符串类型(Unicode类型的),所以你只需要 () 就可以了。 Notes Python 2 Python 3 u() () 元类( METACLASS )# 在Python 2里,你可以通过在类的声明中定义 metaclass 参数,或者定义一个特殊的类级别的 (class-level) __metaclass__ 属性,来创建元类。在Python 3里, __metaclass__ 属性已经被取消了。 Notes Python 2 Python 3 unchanged class C(metaclass=PapayaMeta): ① pass class Whip: ② __metaclass__ = PapayaMeta class C(Whipper, Beater): __metaclass__ = PapayaMeta ③ class Whip(metaclass=PapayaMeta): pass class C(Whipper, Beater, metaclass=PapayaMeta): pass 1. 在声明类的时候声明 metaclass 参数,这在Python 2和Python 3里都有效,它们是一样的。 2. 在类的定义里声明 __metaclass__ 属性在Python 2里有效,但是在Python 3里不再有效。 3. 2to3 能够构建一个有效的类声明,即使这个类继承自多个父类。 关于代码风格# 以下所列的“修补”(fixes)实质上并不算真正的修补。意思就是,他们只是代码的风格上的事情,而不 涉及到代码的本质。但是Python的开发者们在使得代码风格尽可能一致方面非常有兴趣(have a vested interest)。为此,有一个专门o描述Python代码风格的官方指导手册 — 细致到能使人痛 苦 — 都是一些你不太可能关心的在各种各样的细节上的挑剔。鉴于 2to3 为转换代码提供了一个这么 好的条件,脚本的作者们添加了一些可选的特性以使你的代码更具可读性。 set() 字面值( LITERAL )(显式的)# 在Python 2城,定义一个字面值集合(literal set)的唯一方法就是调用 set(a_sequence) 。在Python 3 里这仍然有效,但是使用新的标注记号(literal notation):大括号({})是一种更清晰的方法。这种方法 除了空集以外都有效,因为字典也用大括号标记,所以 {} 表示一个空的字典,而不是一个空集。 ☞ 2to3 脚本默认不会修复 set() 字面值。为了开启这个功能,在命令行调用 2to3 的时候指定 -f set_literal 参数。 Notes Before After set([1, 2, 3]) set((1, 2, 3)) set([i for i in a_sequence]) {1, 2, 3} {1, 2, 3} {i for i in a_sequence} 全局函数 buffer() (显式的)# 用C实现的Python对象可以导出一个“缓冲区接口”(buffer interface),它允许其他的Python代码直 接读写一块内存。(这听起来很强大,它也同样可怕。)在Python 3里, buffer() 被重新命名为 memoryview() 。(实际的修改更加复杂,但是你几乎可以忽略掉这些不同之处。) ☞ 2to3 脚本默认不会修复 buffer() 函数。为了开启这个功能,在命令行调用 2to3 的时候指定 -f buffer 参数。 Notes Before After x = buffer(y) x = memoryview(y) 逗号周围的空格(显式的)# 尽管Python对用于缩进和凸出(indenting and outdenting)的空格要求很严格,但是对于空格在其他 方面的使用Python还是很自由的。在列表,元组,集合和字典里,空格可以出现在逗号的前面或者 后面,这不会有什么坏影响。但是,Python代码风格指导手册上指出,逗号前不能有空格,逗号后 应该包含一个空格。尽管这纯粹只是一个美观上的考量(代码仍然可以正常工作,在Python 2和 Python 3里都可以),但是 2to3 脚本可以依据手册上的标准为你完成这个修复。 ☞ 2to3 脚本默认不会修复逗号周围的空格。为了开启这个功能,在命令行调用 2to3 的时候指定 -f wscomma 参数。 Notes Before After a ,b {a :b} a, b {a: b} 惯例(C OMMON IDIOMS )(显式的)# 在Python社区里建立起来了许多惯例。有一些比如 while 1: loop,它可以追溯到Python 1。(Python 直到Python 2.3才有真正意义上的布尔类型,所以开发者以前使用 1 和 0 替代。)当代的Python程序 员应该锻炼他们的大脑以使用这些惯例的现代版。 ☞ 2to3 脚本默认不会为这些惯例做修复。为了开启这个功能,在命令行调用 2to3 的时候指定 -f idioms 参数。 Notes Before After while 1: do_stuff() type(x) == T type(x) is T while True: do_stuff() isinstance(x, T) isinstance(x, T) a_list = list(a_sequence) a_() a_list = sorted(a_sequence) do_stuff(a_list) do_stuff(a_list)

发布评论