Python2与Python3的区别详解


Posted in Python onFebruary 09, 2020

许多Python初学者都会问:我应该学习哪个版本的Python。对于这个问题,我的回答通常是“先选择一个最适合你的Python教程,教程中使用哪个版本的Python,你就用那个版本。等学得差不多了,再来研究不同版本之间的差别”。

但如果想要用Python开发一个新项目,那么该如何选择Python版本呢?我可以负责任的说,大部分Python库都同时支持Python 2.7.x和3.x版本的,所以不论选择哪个版本都是可以的。但为了在使用Python时避开某些版本中一些常见的陷阱,或需要移植某个Python项目时,依然有必要了解一下Python两个常见版本之间的主要区别。

本节内容

  • 使用__future__模块
  • print函数
  • 整数除法
  • Unicode
  • xrange
  • 触发异常
  • 处理异常
  • next()函数和.next()方法
  • For循环变量与全局命名空间泄漏
  • 比较无序类型
  • 使用input()解析输入内容
  • 返回可迭代对象,而不是列表

一、__future__模块

Python 3.x引入了一些与Python 2不兼容的关键字和特性,在Python 2中,可以通过内置的__future__模块导入这些新内容。如果你希望在Python 2环境下写的代码也可以在Python 3.x中运行,那么建议使用__future__模块。例如,如果希望在Python 2中拥有Python 3.x的整数除法行为,可以通过下面的语句导入相应的模块。

from __future__ import division

下表列出了__future__中其他可导入的特性:

特性 可选版本 强制版本 效果
nested_scopes 2.1.0b1 2.2 PEP 227:Statically Nested Scopes
generators 2.2.0a1 2.3 PEP 255:Simple Generators
division 2.2.0a2 3.0 PEP 238:Changing the Division Operator
absolute_import 2.5.0a1 3.0 PEP 328:Imports: Multi-Line and Absolute/Relative
with_statement 2.5.0a1 2.6 PEP 343:The “with” Statement
print_function 2.6.0a2 3.0 PEP 3105:Make print a function
unicode_literals 2.6.0a2 3.0 PEP 3112:Bytes literals in Python 3000

(来源: https://docs.python.org/2/library/future.html)

示例:

from platform import python_version

二、print函数

虽然print语法是Python 3中一个很小的改动,且应该已经广为人知,但依然值得提一下:Python 2中的print语句被Python 3中的print()函数取代,这意味着在Python 3中必须用括号将需要输出的对象括起来。

在Python 2中使用额外的括号也是可以的。但反过来在Python 3中想以Python2的形式不带括号调用print函数时,会触发SyntaxError。

Python 2

print 'Python', python_version()
print 'Hello, World!'
print('Hello, World!')
print "text", ; print 'print more text on the same line'
Python 2.7.6
Hello, World!
Hello, World!
text print more text on the same line

Python 3

print('Python', python_version())
print('Hello, World!')

print("some text,", end="") 
print(' print more text on the same line')
Python 3.4.1
Hello, World!
some text, print more text on the same line
print 'Hello, World!'
File "<ipython-input-3-139a7c5835bd>", line 1
print 'Hello, World!'
^
SyntaxError: invalid syntax

注意:

在Python中,带不带括号输出”Hello World”都很正常。但如果在圆括号中同时输出多个对象时,就会创建一个元组,这是因为在Python 2中,print是一个语句,而不是函数调用。

print 'Python', python_version()
print('a', 'b')
print 'a', 'b'

三、整数除法

由于人们常常会忽视Python 3在整数除法上的改动(写错了也不会触发Syntax Error),所以在移植代码或在Python 2中执行Python 3的代码时,需要特别注意这个改动。

所以,我还是会在Python 3的脚本中尝试用float(3)/2或 3/2.0代替3/2,以此来避免代码在Python 2环境下可能导致的错误(或与之相反,在Python 2脚本中用from __future__ import division来使用Python 3的除法)。

Python 2

print 'Python', python_version()
print '3 / 2 =', 3 / 2
print '3 // 2 =', 3 // 2
print '3 / 2.0 =', 3 / 2.0
print '3 // 2.0 =', 3 // 2.0

Python 3

print('Python', python_version())
print('3 / 2 =', 3 / 2)
print('3 // 2 =', 3 // 2)
print('3 / 2.0 =', 3 / 2.0)
print('3 // 2.0 =', 3 // 2.0)

四、Unicode

Python 2有基于ASCII的str()类型,其可通过单独的unicode()函数转成unicode类型,但没有byte类型。

而在Python 3中,终于有了Unicode(utf-8)字符串,以及两个字节类:bytes和bytearrays。

Python 2

print 'Python', python_version()

print type(unicode('this is like a python3 str type'

print type(b'byte type does not exist')

print 'they are really' + b' the same'

print type(bytearray(b'bytearray oddly does exist though'))

Python 3

print('Python', python_version())

print('strings are now utf-8 u03BCnicou0394é!') 

print('Python', python_version(), end="")

print(' has', type(b' bytes for storing data'))
 

print('and Python', python_version(), end="")

print(' also has', type(bytearray(b'bytearrays'))
 

'note that we cannot add a string' + b'bytes for data'

五、xrange

在Python 2.x中,经常会用xrange()创建一个可迭代对象,通常出现在“for循环”或“列表/集合/字典推导式”中。

这种行为与生成器非常相似(如”惰性求值“),但这里的xrange-iterable无尽的,意味着可能在这个xrange上无限迭代。

由于xrange的“惰性求知“特性,如果只需迭代一次(如for循环中),range()通常比xrange()快一些。不过不建议在多次迭代中使用range(),因为range()每次都会在内存中重新生成一个列表。

在Python 3中,range()的实现方式与xrange()函数相同,所以就不存在专用的xrange()(在Python 3中使用xrange()会触发NameError)。

import timeit
 
n = 10000
def test_range(n):
 return for i in range(n):
 pass
 
def test_xrange(n):
 for i in xrange(n):
 pass

Python 2

print 'Python', python_version()
 
print 'ntiming range()'
%timeit test_range(n)
 
print 'nntiming xrange()'
%timeit test_xrange(n)

Python 3

print('Python', python_version())
 
print('ntiming range()')
%timeit test_range(n)
 
print(xrange(10))

六、Python 3中的range对象中的__contains__方法

另一个值得一提的是,在Python 3.x中,range有了一个新的__contains__方法。__contains__方法可以有效的加快Python 3.x中整数和布尔型的“查找”速度。

x = 10000000
def val_in_range(x, val):
 return val in range(x)
 
def val_in_xrange(x, val):
 return val in xrange(x)
 
print('Python', python_version())
assert(val_in_range(x, x/2) == True)
assert(val_in_range(x, x//2) == True)
%timeit val_in_range(x, x/2)
%timeit val_in_range(x, x//2)

根据上面的timeit的结果,查找整数比查找浮点数要快大约6万倍。但由于Python 2.x中的range或xrange没有__contains__方法,所以在Python 2中的整数和浮点数的查找速度差别不大。

print 'Python', python_version()
 
assert(val_in_xrange(x, x/2.0) == True)
assert(val_in_xrange(x, x/2) == True)
assert(val_in_range(x, x/2) == True)
assert(val_in_range(x, x//2) == True)
%timeit val_in_xrange(x, x/2.0)
%timeit val_in_xrange(x, x/2)
%timeit val_in_range(x, x/2.0)
%timeit val_in_range(x, x/2)

下面的代码证明了Python 2.x中没有__contain__方法:

print('Python', python_version())
range.__contains__
 
print('Python', python_version())
range.__contains__
 
print('Python', python_version())
xrange.__contains__

关于Python 2中xrange()与Python 3中range()之间的速度差异的一点说明:

有读者指出了Python 3中的range()和Python 2中xrange()执行速度有差异。由于这两者的实现方式相同,因此理论上执行速度应该也是相同的。这里的速度差别仅仅是因为Python 3的总体速度就比Python 2慢。

def test_while():
 i = 0
 while i < 20000:
 i += 1
 return
 
print('Python', python_version())
%timeit test_while()
 
print 'Python', python_version()
%timeit test_while()

   

七、触发异常

Python 2支持新旧两种异常触发语法,而Python 3只接受带括号的的语法(不然会触发SyntaxError):

Python 2

print 'Python', python_version(
 
raise IOError, "file error"
 
raise IOError("file error")

Python 3

print('Python', python_version())
 
raise IOError, "file error"
 
print('Python', python_version())
raise IOError("file error")

八、异常处理

Python 3中的异常处理也发生了一点变化。在Python 3中必须使用“as”关键字。

Python 2

print 'Python', python_version()
try:
 let_us_cause_a_NameError
except NameError, err:
 print err, '--> our error message'

Python 3

print('Python', python_version())
try:
 let_us_cause_a_NameError
except NameError as err:
 print(err, '--> our error message')

next()函数和.next()方法

由于会经常用到next()(.next())函数(方法),所以还要提到另一个语法改动(实现方面也做了改动):在Python 2.7.5中,函数形式和方法形式都可以使用,而在Python 3中,只能使用next()函数(试图调用.next()方法会触发AttributeError)。

Python 2

print 'Python', python_version()
my_generator = (letter for letter in 'abcdefg')
next(my_generator)
my_generator.next()

Python 3

print('Python', python_version())
my_generator = (letter for letter in 'abcdefg')
next(my_generator)
 
my_generator.next()

九、For循环变量与全局命名空间泄漏

好消息是:在Python 3.x中,for循环中的变量不再会泄漏到全局命名空间中了!

这是Python 3.x中做的一个改动,在“What's New In Python 3.0”中有如下描述:

“列表推导不再支持[… for var in item1, item2, …]这样的语法,使用[… for var in (item1, item2, …)]代替。还要注意列表推导有不同的语义:现在列表推导更接近list()构造器中的生成器表达式这样的语法糖,特别要注意的是,循环控制变量不会再泄漏到循环周围的空间中了。”

Python 2

print 'Python', python_version()
 
i = 1
print 'before: i =', i
 
print 'comprehension: ', [i for i in range(5)]
 
print 'after: i =', i

Python 3

print('Python', python_version())
 
i = 1
print('before: i =', i)
 
print('comprehension:', [i for i in range(5)])
 
print('after: i =', i)

十、比较无序类型

Python 3中另一个优秀的改动是,如果我们试图比较无序类型,会触发一个TypeError。

Python 2

print 'Python', python_version()
print "[1, 2] > 'foo' = ", [1, 2] > 'foo'
print "(1, 2) > 'foo' = ", (1, 2) > 'foo'
print "[1, 2] > (1, 2) = ", [1, 2] > (1, 2)

Python 3

print('Python', python_version())
print("[1, 2] > 'foo' = ", [1, 2] > 'foo')
print("(1, 2) > 'foo' = ", (1, 2) > 'foo')
print("[1, 2] > (1, 2) = ", [1, 2] > (1, 2))

十一、通过input()解析用户的输入

幸运的是,Python 3改进了input()函数,这样该函数就会总是将用户的输入存储为str对象。在Python 2中,为了避免读取非字符串类型会发生的一些危险行为,不得不使用raw_input()代替input()。

Python 2

Python 2.7.6
[GCC 4.0.1 (Apple Inc. build 5493)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
 
>>> my_input = input('enter a number: ')
 
enter a number: 123
 
>>> type(my_input)
<type 'int'>
 
>>> my_input = raw_input('enter a number: ')
 
enter a number: 123
 
>>> type(my_input)
<type 'str'>

Python 3

Python 3.4.1
[GCC 4.2.1 (Apple Inc. build 5577)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
 
>>> my_input = input('enter a number: ')
enter a number: 123
>>> type(my_input)
<class 'str'>

十二、返回可迭代对象,而不是列表

在xrange一节中可以看到,某些函数和方法在Python中返回的是可迭代对象,而不像在Python 2中返回列表。

由于通常对这些对象只遍历一次,所以这种方式会节省很多内存。然而,如果通过生成器来多次迭代这些对象,效率就不高了。

此时我们的确需要列表对象,可以通过list()函数简单的将可迭代对象转成列表。

Python 2

print 'Python', python_version()
 
print range(3)
print type(range(3))

Python 3

print('Python', python_version())
print(range(3))
print(type(range(3)))
print(list(range(3)))

下面列出了Python 3中其他不再返回列表的常用函数和方法:

  • zip()
  • map()
  • filter()
  • 字典的.key()方法
  • 字典的.value()方法

更多关于python2和3区别请查看下面的相关链接

Python 相关文章推荐
spark: RDD与DataFrame之间的相互转换方法
Jun 07 Python
Flask之flask-session的具体使用
Jul 26 Python
Django如何自定义分页
Sep 25 Python
Python面向对象基础入门之编码细节与注意事项
Dec 11 Python
python交换两个变量的值方法
Jan 12 Python
详解python--模拟轮盘抽奖游戏
Apr 12 Python
python binascii 进制转换实例
Jun 12 Python
python读出当前时间精度到秒的代码
Jul 05 Python
python2与python3爬虫中get与post对比解析
Sep 18 Python
Python实现读取并写入Excel文件过程解析
May 27 Python
tensorflow使用CNN分析mnist手写体数字数据集
Jun 17 Python
删除pycharm鼠标右键快捷键打开项目的操作
Jan 16 Python
python默认参数调用方法解析
Feb 09 #Python
Python集合操作方法详解
Feb 09 #Python
Python字符编码转码之GBK,UTF8互转
Feb 09 #Python
Python基础之字符串操作常用函数集合
Feb 09 #Python
python连接PostgreSQL过程解析
Feb 09 #Python
Python +Selenium解决图片验证码登录或注册问题(推荐)
Feb 09 #Python
python+selenium定时爬取丁香园的新型冠状病毒数据并制作出类似的地图(部署到云服务器)
Feb 09 #Python
You might like
PHP+SQL 注入攻击的技术实现以及预防办法
2010/12/29 PHP
PHP四大安全策略
2014/03/12 PHP
Yii2主题(Theme)用法详解
2016/07/23 PHP
PHP依赖注入(DI)和控制反转(IoC)详解
2017/06/12 PHP
Javascript 获取LI里的内容
2008/12/17 Javascript
了解一点js的Eval函数
2012/07/26 Javascript
node.js中的path.join方法使用说明
2014/12/08 Javascript
Javascript中For In语句用法实例
2015/05/14 Javascript
基于jQuery Ajax实现上传文件
2016/03/24 Javascript
JavaScript学习笔记--常用的互动方法
2016/12/07 Javascript
Angular5给组件本身的标签添加样式class的方法
2018/04/07 Javascript
一个Vue视频媒体多段裁剪组件的实现示例
2018/08/09 Javascript
解决vue项目nginx部署到非根目录下刷新空白的问题
2018/09/27 Javascript
React 组件渲染和更新的实现代码示例
2019/02/21 Javascript
vue-cli3配置favicon.ico和title的流程
2020/10/27 Javascript
Vue与React的区别和优势对比
2020/12/18 Vue.js
python实现的文件同步服务器实例
2015/06/02 Python
python+ffmpeg批量去视频开头的方法
2019/01/09 Python
详解Python3注释知识点
2019/02/19 Python
python爬取基于m3u8协议的ts文件并合并
2019/04/26 Python
python中property属性的介绍及其应用详解
2019/08/29 Python
python生成特定分布数的实例
2019/12/05 Python
Python数据相关系数矩阵和热力图轻松实现教程
2020/06/16 Python
Python应用自动化部署工具Fabric原理及使用解析
2020/11/30 Python
详解FireFox下Canvas使用图像合成绘制SVG的Bug
2019/07/10 HTML / CSS
英国著名的小众美容品牌网站:Alyaka
2017/08/08 全球购物
英国剑桥包中文官网:The Cambridge Satchel Company中国
2018/11/06 全球购物
运动会通讯稿50字
2014/01/30 职场文书
经济担保书范文
2014/04/02 职场文书
优秀安全员事迹材料
2014/05/11 职场文书
大学生标准自荐书
2014/06/15 职场文书
综合办公室主任岗位职责
2015/04/01 职场文书
2015年计划生育协会工作总结
2015/05/13 职场文书
中国梦党课学习心得体会
2016/01/05 职场文书
四年级数学教学反思
2016/02/16 职场文书
MySQL pt-slave-restart工具的使用简介
2021/04/07 MySQL