文档章节

Python3和2常用语句的语法区别2.0

御前带刀红衬衫
 御前带刀红衬衫
发布于 2016/05/08 16:04
字数 4847
阅读 106
收藏 9

返回列表的字典类方法#

在Python 2里,许多字典类方法的返回值是列表。其中最常用方法的有keysitemsvalues。在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 iin a_dictionary.iterkeys()] [i for iin a_dictionary.keys()]
min(a_dictionary.keys()) no change
  1. 使用list()函数将keys()的返回值转换为一个静态列表,出于安全方面的考量,2to3可能会报错。这样的代码是有效的,但是对于使用视图来说,它的效率低一些。你应该检查转换后的代码,看看是否一定需要列表,也许视图也能完成同样的工作。

  2. 这是另外一种视图(关于items()方法的)到列表的转换。2to3values()方法返回值的转换也是一样的。

  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 http.client
import Cookie import http.cookies
import cookielib import http.cookiejar
import BaseHTTPServerimport SimpleHTTPServerimport CGIHttpServer
import http.server
  1. http.client模块实现了一个底层的库,可以用来请求HTTP资源,解析HTTP响应。

  2. http.cookies模块提供一个蟒样的(Pythonic)接口来获取通过HTTP头部(HTTP header)Set-Cookie发送的cookies

  3. 常用的流行的浏览器会把cookies以文件形式存放在磁盘上,http.cookiejar模块可以操作这些文件。

  4. 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 FancyURLopenerfrom urllib import urlencode
from urllib.request import FancyURLopenerfrom urllib.parse import urlencode
from urllib2 import Requestfrom urllib2 import HTTPError
from urllib.request import Requestfrom urllib.error 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里的urllib.parse模块包含了原来Python 2里urlparse模块所有的解析函数。

  4. urllib.robotparse模块解析robots.txt文件

  5. 处理HTTP重定向和其他状态码的FancyURLopener类在Python 3里的urllib.request模块里依然有效。urlencode()函数已经被转移到了urllib.parse里。

  6. Request对象在urllib.request里依然有效,但是像HTTPError这样的常量已经被转移到了urllib.error里。

我是否有提到2to3也会重写你的函数调用?比如,如果你的Python 2代码里导入了urllib模块,调用了urllib.urlopen()函数获取数据,2to3会同时修改import语句和函数调用。

Notes Python 2 Python 3
 
import urllibprint urllib.urlopen('http://diveintopython3.org/').read()
import urllib.request, urllib.parse, urllib.errorprint(urllib.request.urlopen('http://diveintopython3.org/').read())

dbm#

所有的DBM克隆(DBM clone)现在在单独的一个包里,即dbm。如果你需要其中某个特定的变体,比如GNUDBM,你可以导入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 anydbmimport whichdb
import dbm

xmlrpc#

XML-RPC是一个通过HTTP协议执行远程RPC调用的轻重级方法。一些XML-RPC客户端和XML-RPC服务端的实现库现在被组合到了独立的包,即xmlrpc

Notes Python 2 Python 3
  import xmlrpclib import xmlrpc.client
 
import DocXMLRPCServerimport SimpleXMLRPCServer
import xmlrpc.server

其他模块#

Notes Python 2 Python 3
try:    import cStringIO as StringIOexcept ImportError:    import StringIO
import io
try:    import cPickle as pickleexcept 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
  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解释器会先在当前目录里搜索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 mbcharsetproberimportMultiByteCharSetProber from .mbcharsetproberimportMultiByteCharsetProber
  1. 当你需要从包的其他地方导入整个模块,使用新的from . import语法。这里的句号(.)即表示当前文件(universaldetector.py)和你想要导入文件(constants.py)之间的相对路径。在这个样例中,这两个文件在同一个目录里,所以使用了单个句号。你也可以从父目录(from .. import anothermodule)或者子目录里导入。

  2. 为了将一个特定的类或者函数从其他模块里直接导入到你的模块的名字空间里,在需要导入的模块名前加上相对路径,并且去掉最后一个斜线(slash)。在这个例子中,mbcharsetprober.pyuniversaldetector.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 = 42for an_iterator in a_sequence_of_iterators:    an_iterator.next()
next = 42for an_iterator in 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))
list(filter(a_function, a_sequence)) no change
filter(None, a_sequence) [i for iin a_sequence if i]
for i in filter(None, a_sequence): no change
[i for iin filter(a_function, a_sequence)] 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') list(map(a_function,'PapayaWhip'))
map(None,'PapayaWhip') list('PapayaWhip')
map(lambda x: x+1, range(42)) [x+1for x in range(42)]
for i in map(a_function, a_sequence): no change
[i for iin map(a_function, a_sequence)] 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()函数不再存在了;必须使用星号标记法。

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)
  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
  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)
  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` repr(x)
`'PapayaWhip' + `2`` repr('PapayaWhip'+ repr(2))
  1. 记住,x可以是任何东西 — 一个类,函数,模块,基本数据类型,等等。repr()函数可以使用任何类型的参数。

  2. 在Python 2里,反引号可以嵌套,导致了这种令人费解的(但是有效的)表达式。2to3足够智能以将这种嵌套调用转换到repr()函数。

try...except语句#

从Python 2到Python 3,捕获异常的语法有些许变化。

Notes Python 2 Python 3
try:    import mymoduleexcept ImportError, e
    pass
try:    import mymoduleexcept ImportError as e:    pass
try:    import mymoduleexcept (RuntimeError, ImportError), e
    pass
try:    import mymoduleexcept (RuntimeError, ImportError) as e:    pass
try:    import mymoduleexcept ImportError:    pass
no change
try:    import mymoduleexcept:    pass
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 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
  1. 抛出不带用户自定义错误信息的异常,这种最简单的形式下,语法没有改变。

  2. 当你想要抛出一个带用户自定义错误信息的异常时,改变就显而易见了。Python 2用一个逗号来分隔异常类和错误信息;Python 3把错误信息作为参数传递给异常类。

  3. Python 2支持一种更加复杂的语法来抛出一个带用户自定义回溯(stack trace,堆栈追踪)的异常。在Python 3里你也可以这样做,但是语法完全不同。

  4. 在Python 2里,你可以抛出一个不带异常类的异常,仅仅只有一个异常信息。在Python 3里,这种形式不再被支持。2to3将会警告你它不能自动修复这种语法。

本文转载自:http://old.sebug.net/paper/books/dive-into-python3/porting-code-to-python-3-with-2to3.html

共有 人打赏支持
御前带刀红衬衫
粉丝 22
博文 15
码字总数 13374
作品 0
南宁
程序员
python3.x与python2.x的区别汇总

python3.x与python2.7.x都是比较流行的版本,虽然建议现在的初学者开始学习python3.x的版本,但是还有很多的工程使用的是python2.7.x版本。观看代码的时候难免会出现一些问题。 在google上搜...

oldpan
2017/10/10
0
0
Python2.x与3.x版本区别

Python的3.0版本,常被称为Python 3000,或简称Py3k。相对于Python的早期版本,这是一个较大的升级。 为了不带入过多的累赘,Python 3.0在设计的时候没有考虑向下相容。 许多针对早期Python版...

Airship
2015/11/12
0
0
python起步之旅【Hello World】

python打卡第一天: Python是什么,我相信网上一搜一大堆,这里我就不介绍了。下面是我的学习记录: 学习一门程序语言,首先大家都会去了解这个语言的发展历史,然后开始先用这个程序语言输出...

白羊IT
06/27
0
0
python2.x和python3.x的区别

Python的3.0版本,常被称为Python3000,或简称Py3k。相对于Python的早期版本,这是一个较大的升级。 为了不带入过多的累赘,Python3.0在设计的时候没有考虑向下相容。许多针对早期Python版本...

leejia1989
06/26
0
0
Supporting Python 3(支持python3)——语言区别和暂时解决方法

语言区别和暂时解决方法 这个附录包含一个Python 2和Python 3的不同之处列表以及能不用2to3转换同时在Python 2和Python 3下运行的示例代码。 这个列表是不完整的。在这里列出的只有不包括bug...

在湖闻樟
2015/11/20
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

idea新建springCloud项目(5)- 订单服务

1.创建订单api,如下: 2.创建订单实现逻辑 3.新建订单、订单商品表 -- 订单 create table `order_master` ( `order_id` varchar(32) not null, `buyer_name` varchar(32) not null comment......

monroeCode
7分钟前
0
0
游戏开发经验谈(二):对战类全球服游戏的设计与实现

上篇文章《游戏开发经验谈(一):游戏架构里隐藏的五个坑及其应对方案》,我们主要讲解了游戏架构设计当中隐藏的一些坑及其应对方案,错过的小伙伴可以回溯之前的内容。本期内容,将会重点介...

UCloudTech
17分钟前
0
0
Mysql基本语法

一.联合主键 drop table CONTENT_AND_CATALOG;CREATE TABLE `tobebetter`.`CONTENT_AND_CATALOG` ( `ID` VARCHAR(120) NOT NULL , `CONTENT_ID` VARCHAR(120) , `CA......

我是菜鸟我骄傲
18分钟前
0
0
179. centos7 安装mariadb

1. centos7 中安装mariadb 1.1 执行安装 centos7 自带了mariadb yum -y install mariadb mariadb-server 1.2 启动mariadb systemctl start mariadb 1.3 设置开机启动 systemctl enable maria......

Lucky_Me
26分钟前
0
0
【AI实战】动手训练自己的目标检测模型(YOLO篇)

在前面的文章中,已经介绍了基于SSD使用自己的数据训练目标检测模型(见文章:手把手教你训练自己的目标检测模型),本文将基于另一个目标检测模型YOLO,介绍如何使用自己的数据进行训练。 ...

雪饼
32分钟前
1
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部