Python3.x和Python2.x的区别
Posted ❦邪恶毅小人❦
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python3.x和Python2.x的区别相关的知识,希望对你有一定的参考价值。
- 使用2to3将代码移植到Python 3
- 概述#
- print语句#
- Unicode字符串#
- 全局函数unicode()#
- long 长整型#
- <> 比较运算符#
- 字典类方法has_key()#
- 返回列表的字典类方法#
- 被重命名或者重新组织的模块#
- http#
- urllib#
- dbm#
- xmlrpc#
- 其他模块#
- 包内的相对导入#
- 迭代器方法next()#
- 全局函数filter()#
- 全局函数map()#
- 全局函数reduce()#
- 全局函数apply()#
- 全局函数intern()#
- exec语句#
- execfile语句#
- repr(反引号)#
- try...except语句#
- raise语句#
- 生成器的throw方法#
- 全局函数xrange()#
- 全局函数raw_input()和input()#
- 函数属性func_*#
- I/O方法xreadlines()#
- 使用元组而非多个参数的lambda函数#
- 特殊的方法属性#
- __nonzero__特殊方法#
- 八进制类型#
- sys.maxint#
- 全局函数callable()#
- 全局函数zip()#
- StandardError异常#
- types模块中的常量#
- 全局函数isinstance()#
- basestring数据类型#
- itertools模块#
- sys.exc_type, sys.exc_value, sys.exc_traceback#
- 对元组的列表解析#
- os.getcwdu()函数#
- 元类(metaclass)#
- 关于代码风格#
- set()字面值(literal)(显式的)#
- 全局函数buffer()(显式的)#
- 逗号周围的空格(显式的)#
- 惯例(Common idioms)(显式的)#
这个星期开始学习Python了,因为看的书都是基于Python2.x,而且我安装的是Python3.1,所以书上写的地方好多都不适用于Python3.1,特意在Google上search了一下3.x和2.x的区别。特此在自己的空间中记录一下,以备以后查找方便,也可以分享给想学习Python的friends.
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 >>sys.stderr, "fatal error"
3.X: print("fatal error", file=sys.stderr)
2.X: print (x, y) # 输出repr((x, y))
3.X: print((x, y)) # 不同于print(x, y)!
7)改变了顺序操作符的行为,例如x<y,当x和y类型不匹配时抛出TypeError而不是返回随即的 bool值
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 (<pyshell#63>, line 1)
>>> 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_a.print = 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)
<type ‘bytes‘>
str对象和bytes对象可以使用.encode() (str -> bytes) or .decode() (bytes -> str)方法相互转化。
>>> s = b.decode()
>>> s
‘china‘
>>> b1 = s.encode()
>>> b1
b‘china‘
3)dict的.keys()、.items 和.values()方法返回迭代器,而之前的iterkeys()等函数都被废弃。同时去掉的还有
dict.has_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 error.message
...
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模块(单独发布,可以从http://www.jcea.es/programacion/pybsddb.htm获取)
5)移除了new模块
6)os.tmpnam()和os.tmpfile()函数被移动到tmpfile模块下
7)tokenize模块现在使用bytes工作。主要的入口点不再是generate_tokens,而是 tokenize.tokenize()
9.其它
1)xrange() 改名为range(),要想使用range()获得一个list,必须显式调用:
>>> list(range(10))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
2)bytes对象不能hash,也不支持 b.lower()、b.strip()和b.split()方法,但对于后两者可以使用 b.strip(b’
\n\t\r \f’)和b.split(b’ ‘)来达到相同目的
3)zip()、map()和filter()都返回迭代器。而apply()、 callable()、coerce()、 execfile()、reduce()和reload
()函数都被去除了
现在可以使用hasattr()来替换 callable(). hasattr()的语法如:hasattr(string, ‘__name__‘)
4)string.letters和相关的.lowercase和.uppercase被去除,请改用string.ascii_letters 等
5)如果x < y的不能比较,抛出TypeError异常。2.x版本是返回伪随机布尔值的
6)__getslice__系列成员被废弃。a[i:j]根据上下文转换为a.__getitem__(slice(I, j))或 __setitem__和
__delitem__调用
7)file类被废弃,在Py2.5中:
>>> file
<type ‘file‘>
在Py3.X中:
>>> file
Traceback (most recent call last):
File "<pyshell#120>", line 1, in <module>
file
NameError: name ‘file‘ is not defined
===========================
难度等级: ♦♦♦♦♦
使用2to3将代码移植到Python 3
? Life is pleasant. Death is peaceful. It’s the transition that’s troublesome. ?
— Isaac Asimov (attributed)
概述#
几乎所有的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) |
③ | print 1, 2 | print(1, 2) |
④ | print 1, 2, | print(1, 2, end=‘ ‘) |
⑤ | print >>sys.stderr, 1, 2, 3 | print(1, 2, 3, file=sys.stderr) |
- 为输出一个空白行,需要调用不带参数的print()。
- 为输出一个单独的值,需要将这这个值作为print()的一个参数就可以了。
- 为输出使用一个空格分隔的两个值,用两个参数调用print()即可。
- 这个例子有一些技巧。在Python 2里,如果你使用一个逗号(,)作为print语句的结尾,它将会用空格分隔输出的结果,然后在输出一个尾随的空格(trailing space),而不输出回车(carriage return)。在Python 3里,通过把end=‘ ‘作为一个关键字参数传给print()可以实现同样的效果。参数end的默认值为‘\n‘,所以通过重新指定end参数的值,可以取消在末尾输出回车符。
- 在Python 2里,你可以通过使用>>pipe_name语法,把输出重定向到一个管道,比如sys.stderr。在Python 3里,你可以通过将管道作为关键字参数file的值传递给print()来完成同样的功能。参数file的默认值为std.stdout,所以重新指定它的值将会使print()输出到一个另外一个管道。
Unicode字符串#
Python 2有两种字符串类型:Unicode字符串和非Unicode字符串。Python 3只有一种类型:Unicode字符串(Unicode strings)。
Notes | Python 2 | Python 3 |
---|---|---|
① | u‘PapayaWhip‘ | ‘PapayaWhip‘ |
② | ur‘PapayaWhip\foo‘ | r‘PapayaWhip\foo‘ |
- Python 2里的Unicode字符串在Python 3里即普通字符串,因为在Python 3里字符串总是Unicode形式的。
- 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 |
---|---|---|
unicode(anything) | str(anything) |
long 长整型#
Python 2有为非浮点数准备的int和long类型。int类型的最大值不能超过sys.maxint,而且这个最大值是平台相关的。可以通过在数字的末尾附上一个L来定义长整型,显然,它比int类型表示的数字范围更大。在Python 3里,只有一种整数类型int,大多数情况下,它很像Python 2里的长整型。由于已经不存在两种类型的整数,所以就没有必要使用特殊的语法去区别他们。
Notes | Python 2 | Python 3 |
---|---|---|
① | x = 1000000000000L | x = 1000000000000 |
② | x = 0xFFFFFFFFFFFFL | x = 0xFFFFFFFFFFFF |
③ | long(x) | int(x) |
④ | type(x) is long | type(x) is int |
⑤ | isinstance(x, long) | isinstance(x, int) |
- 在Python 2里的十进制长整型在Python 3里被替换为十进制的普通整数。
- 在Python 2里的十六进制长整型在Python 3里被替换为十六进制的普通整数。
- 在Python 3里,由于长整型已经不存在了,自然原来的long()函数也没有了。为了强制转换一个变量到整型,可以使用int()函数。
- 检查一个变量是否是整型,获得它的数据类型,并与一个int类型(不是long)的作比较。
- 你也可以使用isinstance()函数来检查数据类型;再强调一次,使用int,而不是long,来检查整数类型。
<> 比较运算符#
Python 2支持<>作为!=的同义词。Python 3只支持!=,不再支持<>了。
Notes | Python 2 | Python 3 |
---|---|---|
① | if x <> y: | if x != y: |
② | if x <> y <> z: | if x != y != z: |
- 简单地比较。
- 相对复杂的三个值之间的比较。
字典类方法has_key()#
在Python 2里,字典对象的has_key()方法用来测试字典是否包含特定的键(key)。Python 3不再支持这个方法了。你需要使用in运算符。
Notes | Python 2 | Python 3 |
---|---|---|
① | a_dictionary.has_key(‘PapayaWhip‘) | ‘PapayaWhip‘ in a_dictionary |
② | a_dictionary.has_key(x) or a_dictionary.has_key(y) | x in a_dictionary or y in a_dictionary |
③ | a_dictionary.has_key(x or y) | (x or y) in a_dictionary |
④ | a_dictionary.has_key(x + y) | (x + y) in a_dictionary |
⑤ | x + a_dictionary.has_key(y) | x + (y in a_dictionary) |
- 最简单的形式。
- 运算符or的优先级高于运算符in,所以这里不需要添加括号。
- 另一方面,出于同样的原因 — or的优先级大于in,这里需要添加括号。(注意:这里的代码与前面那行完全不同。Python会先解释x or y,得到结果x(如果x在布尔上下文里的值是真)或者y。然后Python检查这个结果是不是a_dictionary的一个键。)
- 运算符in的优先级大于运算符+,所以代码里的这种形式从技术上说不需要括号,但是2to3还是添加了。
- 这种形式一定需要括号,因为in的优先级大于+。
返回列表的字典类方法#
在Python 2里,许多字典类方法的返回值是列表。其中最常用方法的有keys,items和values。在Python 3里,所有以上方法的返回值改为动态视图(dynamic view)。在一些上下文环境里,这种改变并不会产生影响。如果这些方法的返回值被立即传递给另外一个函数,并且那个函数会遍历整个序列,那么以上方法的返回值是列表或者视图并不会产生什么不同。在另外一些情况下,Python 3的这些改变干系重大。如果你期待一个能被独立寻址元素的列表,那么Python 3的这些改变将会使你的代码卡住(choke),因为视图(view)不支持索引(indexing)。
Notes | Python 2 | Python 3 |
---|---|---|
① | a_dictionary.keys() | list(a_dictionary.keys()) |
② | a_dictionary.items() | list(a_dictionary.items()) |
③ | a_dictionary.iterkeys() | iter(a_dictionary.keys()) |
④ | [i for i in a_dictionary.iterkeys()] | [i for i in a_dictionary.keys()] |
⑤ | min(a_dictionary.keys()) | no change |
- 使用list()函数将keys()的返回值转换为一个静态列表,出于安全方面的考量,2to3可能会报错。这样的代码是有效的,但是对于使用视图来说,它的效率低一些。你应该检查转换后的代码,看看是否一定需要列表,也许视图也能完成同样的工作。
- 这是另外一种视图(关于items()方法的)到列表的转换。2to3对values()方法返回值的转换也是一样的。
- Python 3里不再支持iterkeys()了。如果必要,使用iter()将keys()的返回值转换成为一个迭代器。
- 2to3能够识别出iterkeys()方法在列表解析里被使用,然后将它转换为Python 3里的keys()方法(不需要使用额外的iter()去包装其返回值)。这样是可行的,因为视图是可迭代的。
- 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 http.client |
② | import Cookie | import http.cookies |
③ | import cookielib | import http.cookiejar |
④ |
import BaseHTTPServer import SimpleHTTPServer import CGIHttpServer |
import http.server |
- http.client模块实现了一个底层的库,可以用来请求http资源,解析http响应。
- http.cookies模块提供一个蟒样的(Pythonic)接口来获取通过http头部(http header)Set-Cookie发送的cookies
- 常用的流行的浏览器会把cookies以文件形式存放在磁盘上,http.cookiejar模块可以操作这些文件。
- http.server模块实现了一个基本的http服务器
urllib#
Python 2有一些用来分析,编码和获取URL的模块,但是这些模块就像老鼠窝一样相互重叠。在Python 3里,这些模块被重构、组合成了一个单独的包,即urllib。
Notes | Python 2 | Python 3 |
---|---|---|
① | import urllib | import urllib.request, urllib.parse, urllib.error |
② | import urllib2 | import urllib.request, urllib.error |
③ | import urlparse | import urllib.parse |
④ | import robotparser | import urllib.robotparser |
⑤ |
from urllib import FancyURLopener from urllib import urlencode |
from urllib.request import FancyURLopener from urllib.parse import urlencode |
⑥ |
from urllib2 import Request from urllib2 import HTTPError |
from urllib.request import Request from urllib.error import HTTPError |
- 以前,Python 2里的urllib模块有各种各样的函数,包括用来获取数据的urlopen(),还有用来将url分割成其组成部分的splittype(),splithost()和splituser()函数。在新的urllib包里,这些函数被组织得更有逻辑性。2to3将会修改这些函数的调用以适应新的命名方案。
- 在Python 3里,以前的urllib2模块被并入了urllib包。同时,以urllib2里各种你最喜爱的东西将会一个不缺地出现在Python 3的urllib模块里,比如build_opener()方法,Request对象,HTTPBasicAuthHandler和friends。
- Python 3里的urllib.parse模块包含了原来Python 2里urlparse模块所有的解析函数。
- urllib.robotparse模块解析robots.txt文件。
- 处理http重定向和其他状态码的FancyURLopener类在Python 3里的urllib.request模块里依然有效。urlencode()函数已经被转移到了urllib.parse里。
- Request对象在urllib.request里依然有效,但是像HTTPError这样的常量已经被转移到了urllib.error里。
我是否有提到2to3也会重写你的函数调用?比如,如果你的Python 2代码里导入了urllib模块,调用了urllib.urlopen()函数获取数据,2to3会同时修改import语句和函数调用。
Notes | Python 2 | Python 3 |
---|---|---|
import urllib print urllib.urlopen(‘http://diveintopython3.org/‘).read() |
import urllib.request, urllib.parse, urllib.error print(urllib.request.urlopen(‘http://diveintopython3.org/‘).read()) |
dbm#
所有的dbm克隆(dbm clone)现在在单独的一个包里,即dbm。如果你需要其中某个特定的变体,比如gnu dbm,你可以导入dbm包中合适的模块。
Notes | Python 2 | Python 3 |
---|---|---|
import dbm | import dbm.ndbm | |
import gdbm | import dbm.gnu | |
import dbhash | import dbm.bsd | |
import dumbdbm | import dbm.dumb | |
import anydbm import whichdb |
import dbm |
xmlrpc#
xml-rpc是一个通过http协议执行远程rpc调用的轻重级方法。一些xml-rpc客户端和xml-rpc服务端的实现库现在被组合到了独立的包,即xmlrpc。
Notes | Python 2 | Python 3 |
---|---|---|
import xmlrpclib | import xmlrpc.client | |
import DocXMLRPCServer import SimpleXMLRPCServer |
import xmlrpc.server |
其他模块#
Notes | Python 2 | Python 3 |
---|---|---|
① |
try: import cStringIO as StringIO except ImportError: import StringIO |
import io |
② |
try: import cPickle as pickle except ImportError: import pickle |
import pickle |
③ | import __builtin__ | import builtins |
④ | import copy_reg | import copyreg |
⑤ | import Queue | import queue |
⑥ | import SocketServer | import socketserver |
⑦ | import ConfigParser | import configparser |
⑧ | import repr | import reprlib |
⑨ | import commands | import subprocess |
- 在Python 2里,你通常会这样做,首先尝试把cStringIO导入作为StringIO的替代,如果失败了,再导入StringIO。不要在Python 3里这样做;io模块会帮你处理好这件事情。它会找出可用的最快实现方法,然后自动使用它。
- 在Python 2里,导入最快的pickle实现也是一个与上边相似的能用方法。在Python 3里,pickle模块会自动为你处理,所以不要再这样做。
- builtins模块包含了在整个Python语言里都会使用的全局函数,类和常量。重新定义builtins模块里的某个函数意味着在每处都重定义了这个全局函数。这听起来很强大,但是同时也是很可怕的。
- copyreg模块为用C语言定义的用户自定义类型添加了pickle模块的支持。
- queue模块实现一个生产者消费者队列(multi-producer, multi-consumer queue)。
- socketserver模块为实现各种socket server提供了通用基础类。
- configparser模块用来解析ini-style配置文件。
- reprlib模块重新实现了内置函数repr(),并添加了对字符串表示被截断前长度的控制。
- subprocess模块允许你创建子进程,连接到他们的管道,然后获取他们的返回值。
包内的相对导入#
包是由一组相关联的模块共同组成的单个实体。在Python 2的时候,为了实现同一个包内模块的相互引用,你会使用import foo或者from foo import Bar。Python 2解释器会先在当前目录里搜索foo.py,然后再去Python搜索路径(sys.path)里搜索。在Python 3里这个过程有一点不同。Python 3不会首先在当前路径搜索,它会直接在Python的搜索路径里寻找。如果你想要包里的一个模块导入包里的另外一个模块,你需要显式地提供两个模块的相对路径。
假设你有如下包,多个文件在同一个目录下:
chardet/ | +--__init__.py | +--constants.py | +--mbcharsetprober.py | +--universaldetector.py
现在假设universaldetector.py需要整个导入constants.py,另外还需要导入mbcharsetprober.py的一个类。你会怎样做?
Notes | Python 2 | Python 3 |
---|---|---|
① | import constants | from . import constants |
② | from mbcharsetprober import MultiByteCharSetProber | from .mbcharsetprober import MultiByteCharsetProber |
- 当你需要从包的其他地方导入整个模块,使用新的from . import语法。这里的句号(.)即表示当前文件(universaldetector.py)和你想要导入文件(constants.py)之间的相对路径。在这个样例中,这两个文件在同一个目录里,所以使用了单个句号。你也可以从父目录(from .. import anothermodule)或者子目录里导入。
- 为了将一个特定的类或者函数从其他模块里直接导入到你的模块的名字空间里,在需要导入的模块名前加上相对路径,并且去掉最后一个斜线(slash)。在这个例子中,mbcharsetprober.py与universaldetector.py在同一个目录里,所以相对路径名就是一个句号。你也可以从父目录(from .. import anothermodule)或者子目录里导入。
迭代器方法next()#
在Python 2里,迭代器有一个next()方法,用来返回序列里的下一项。在Python 3里这同样成立,但是现在有了一个新的全局的函数next(),它使用一个迭代器作为参数。
Notes | Python 2 | Python 3 |
---|---|---|
① | anIterator.next() | next(anIterator) |
② | a_function_that_returns_an_iterator().next() | next(a_function_that_returns_an_iterator()) |
③ |
class A: def next(self): pass |
class A: def __next__(self): pass |
④ |
class A: def next(self, x, y): pass |
no change |
⑤ |
next = 42 for an_iterator in a_sequence_of_iterators: an_iterator.next() |
next = 42 for an_iterator in a_sequence_of_iterators: an_iterator.__next__() |
- 最简单的例子,你不再调用一个迭代器的next()方法,现在你将迭代器自身作为参数传递给全局函数next()。
- 假如你有一个返回值是迭代器的函数,调用这个函数然后把结果作为参数传递给next()函数。(2to3脚本足够智能以正确执行这种转换。)
- 假如你想定义你自己的类,然后把它用作一个迭代器,在Python 3里,你可以通过定义特殊方法__next__()来实现。
- 如果你定义的类里刚好有一个next(),它使用一个或者多个参数,2to3执行的时候不会动它。这个类不能被当作迭代器使用,因为它的next()方法带有参数。
- 这一个有些复杂。如果你恰好有一个叫做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)) |
② | list(filter(a_function, a_sequence)) | no change |
③ | filter(None, a_sequence) | [i for i in a_sequence if i] |
④ | for i in filter(None, a_sequence): | no change |
⑤ | [i for i in filter(a_function, a_sequence)] | no change |
- 最简单的情况下,2to3会用一个list()函数来包装filter(),list()函数会遍历它的参数然后返回一个列表。
- 然而,如果filter()调用已经被list()包裹,2to3不会再做处理,因为这种情况下filter()的返回值是否是一个迭代器是无关紧要的。
- 为了处理filter(None, ...)这种特殊的语法,2to3会将这种调用从语法上等价地转换为列表解析。
- 由于for循环会遍历整个序列,所以没有必要再做修改。
- 与上面相同,不需要做修改,因为列表解析会遍历整个序列,即使filter()返回一个迭代器,它仍能像以前的filter()返回列表那样正常工作。
全局函数map()#
跟filter()作的改变一样,map()函数现在返回一个迭代器。(在Python 2里,它返回一个列表。)
Notes | Python 2 | Python 3 |
---|---|---|
① | map(a_function, ‘PapayaWhip‘) | list(map(a_function, ‘PapayaWhip‘)) |
② | map(None, ‘PapayaWhip‘) | list(‘PapayaWhip‘) |
③ | map(lambda x: x+1, range(42)) | [x+1 for x in range(42)] |
④ | for i in map(a_function, a_sequence): | no change |
⑤ | [i for i in map(a_function, a_sequence)] | no change |
- 类似对filter()的处理,在最简单的情况下,2to3会用一个list()函数来包装map()调用。
- 对于特殊的map(None, ...)语法,跟filter(None, ...)类似,2to3会将其转换成一个使用list()的等价调用
- 如果map()的第一个参数是一个lambda函数,2to3会将其等价地转换成列表解析。
- 对于会遍历整个序列的for循环,不需要做改变。
- 再一次地,这里不需要做修改,因为列表解析会遍历整个序列,即使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()函数不再存在了;必须使用星号标记法。
Notes | Python 2 | Python 3 |
---|---|---|
① | apply(a_function, a_list_of_args) | a_function(*a_list_of_args) |
② | apply(a_function, a_list_of_args, a_dictionary_of_named_args) | a_function(*a_list_of_args, **a_dictionary_of_named_args) |
③ | apply(a_function, a_list_of_args + z) | a_function(*a_list_of_args + z) |
④ | apply(aModule.a_function, a_list_of_args) | aModule.a_function(*a_list_of_args) |
- 最简单的形式,可以通过在参数列表(就像[a, b, c]一样)前添加一个星号来调用函数。这跟Python 2里的apply()函数是等价的。
- 在Python 2里,apply()函数实际上可以带3个参数:一个函数,一个参数列表,一个字典命名参数(dictionary of named arguments)。在Python 3里,你可以通过在参数列表前添加一个星号(*),在字典命名参数前添加两个星号(**)来达到同样的效果。
- 运算符+在这里用作连接列表的功能,它的优先级高于运算符*,所以没有必要在a_list_of_args + z周围添加额外的括号。
- 2to3脚本足够智能来转换复杂的apply()调用,包括调用导入模块里的函数。
全局函数intern()#
在Python 2里,你可以用intern()函数作用在一个字符串上来限定(intern)它以达到性能优化。在Python 3里,intern()函数被转移到sys模块里了。
Notes | Python 2 | Python 3 |
---|---|---|
intern(aString) | sys.intern(aString) |
exec语句#
就像print语句在Python 3里变成了一个函数一样,exec语句也是这样的。exec()函数使用一个包含任意Python代码的字符串作为参数,然后就像执行语句或者表达式一样执行它。exec()跟eval()是相似的,但是exec()更加强大并更具有技巧性。eval()函数只能执行单独一条表达式,但是exec()能够执行多条语句,导入(import),函数声明 — 实际上整个Python程序的字符串表示也可以。
Notes | Python 2 | Python 3 |
---|---|---|
① | exec codeString | exec(codeString) |
② | exec codeString in a_global_namespace | exec(codeString, a_global_namespace) |
③ | exec codeString in a_global_namespace, a_local_namespace | exec(codeString, a_global_namespace, a_local_namespace) |
- 在最简单的形式下,因为exec()现在是一个函数,而不是语句,2to3会把这个字符串形式的代码用括号围起来。
- Python 2里的exec语句可以指定名字空间,代码将在这个由全局对象组成的私有空间里执行。Python 3也有这样的功能;你只需要把这个名字空间作为第二个参数传递给exec()函数。
- 更加神奇的是,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` | repr(x) |
② | `‘PapayaWhip‘ + `2`` | repr(‘PapayaWhip‘ + repr(2)) |
- 记住,x可以是任何东西 — 一个类,函数,模块,基本数据类型,等等。repr()函数可以使用任何类型的参数。
- 在Python 2里,反引号可以嵌套,导致了这种令人费解的(但是有效的)表达式。2to3足够智能以将这种嵌套调用转换到repr()函数。
try...except语句#
从Python 2到Python 3,捕获异常的语法有些许变化。
Notes | Python 2 | Python 3 |
---|---|---|
① |
try: import mymodule except ImportError, e pass |
try: import mymodule except ImportError as e: pass |
② |
try: import mymodule except (RuntimeError, ImportError), e pass |
try: import mymodule except (RuntimeError, ImportError) as e: pass |
③ |
try: import mymodule except ImportError: pass |
no change |
④ |
try: import mymodule except: pass |
no change |
- 相对于Python 2里在异常类型后添加逗号,Python 3使用了一个新的关键字,as。
- 关键字as也可以用在一次捕获多种类型异常的情况下。
- 如果你捕获到一个异常,但是并不在意访问异常对象本身,Python 2和Python 3的语法是一样的。
- 类似地,如果你使用一个保险方法(fallback)来捕获所有异常,Python 2和Python 3的语法是一样的。
?在导入模块(或者其他大多数情况)的时候,你绝对不应该使用这种方法(指以上的fallback)。不然的话,程序可能会捕获到像KeyboardInterrupt(如果用户按Ctrl-C来中断程序)这样的异常,从而使调试变得更加困难。
raise语句#
Python 3里,抛出自定义异常的语法有细微的变化。
Notes | Python 2 | Python 3 |
---|---|---|
① | raise MyException | unchanged |
② | raise MyException, ‘error message‘ | raise MyException(‘error message‘) |
③ | raise MyException, ‘error message‘, a_traceback | raise MyException(‘error message‘).with_traceback(a_traceback) |
④ | raise ‘error message‘ | unsupported |
- 抛出不带用户自定义错误信息的异常,这种最简单的形式下,语法没有改变。
- 当你想要抛出一个带用户自定义错误信息的异常时,改变就显而易见了。Python 2用一个逗号来分隔异常类和错误信息;Python 3把错误信息作为参数传递给异常类。
- Python 2支持一种更加复杂的语法来抛出一个带用户自定义回溯(stack trace,堆栈追踪)的异常。在Python 3里你也可以这样做,但是语法完全不同。
- 在Python 2里,你可以抛出一个不带异常类的异常,仅仅只有一个异常信息。在Python 3里,这种形式不再被支持。2to3将会警告你它不能自动修复这种语法。
生成器的throw方法#
在Python 2里,生成器有一个throw()方法。调用a_generator.throw()会在生成器被暂停的时候抛出一个异常,然后返回由生成器函数获取的下一个值。在Python 3里,这种功能仍然可用,但是语法上有一点不同。
Notes | Python 2 | Python 3 |
---|---|---|
① | a_generator.throw(MyException) | no change |
② | a_generator.throw(MyException, ‘error message‘) | a_generator.throw(MyException(‘error message‘)) |
③ | a_generator.throw(‘error message‘) | unsupported |
- 最简单的形式下,生成器抛出不带用户自定义错误信息的异常。这种情况下,从Python 2到Python 3语法上没有变化 。
- 如果生成器抛出一个带用户自定义错误信息的异常,你需要将这个错误信息字符串(error string)传递给异常类来以实例化它。
- Python 2还支持抛出只有异常信息的异常。Python 3不支持这种语法,并且2to3会显示一个警告信息,告诉你需要手动地来修复这处代码。
全局函数xrange()#
在Python 2里,有两种方法来获得一定范围内的数字:range(),它返回一个列表,还有range(),它返回一个迭代器。在Python 3里,range()返回迭代器,xrange()不再存在了。
Notes | Python 2 | Python 3 |
---|---|---|
① | xrange(10) | range(10) |
② | a_list = range(10) | a_list = list(range(10)) |
③ | [i for i in xrange(10)] | [i for i in range(10)] |
④ | for i in range(10): | no change |
⑤ | sum(range(10)) | no change |
- 在最简单的情况下,2to3会简单地把xrange()转换为range()。
- 如果你的Python 2代码使用range(),2to3不知道你是否需要一个列表,或者是否一个迭代器也行。出于谨慎,2to3可能会报错,然后使用list()把range()的返回值强制转换为列表类型。
- 如果在列表解析里有xrange()函数,就没有必要将其返回值转换为一个列表,因为列表解析对迭代器同样有效。
- 类似的,for循环也能作用于迭代器,所以这里也没有改变任何东西。
- 函数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() | input() |
② | raw_input(‘prompt‘) | input(‘prompt‘) |
③ | input() | eval(input()) |
- 最简单的形式,raw_input()被替换成input()。
- 在Python 2里,raw_input()函数可以指定一个提示符作为参数。Python 3里保留了这个功能。
- 如果你真的想要请求用户输入一个Python表达式,计算结果,可以通过调用input()函数然后把返回值传递给eval()。
函数属性func_*#
在Python 2里,函数的里的代码可以访问到函数本身的特殊属性。在Python 3里,为了一致性,这些特殊属性被重新命名了。
Notes | Python 2 | Python 3 |
---|---|---|
① | a_function.func_name | a_function.__name__ |
② | a_function.func_doc | a_function.__doc__ |
③ | a_function.func_defaults | a_function.__defaults__ |
④ | a_functio 以上是关于Python3.x和Python2.x的区别的主要内容,如果未能解决你的问题,请参考以下文章 |