目录

文章目录

  • 目录
  • 前言
  • Python 2 or 3 ?
  • Python Future 的兼容性
    • __future__ Module
    • future Package
  • 统一不等于语法
  • 统一整数类型
  • 统一整数除法
  • 统一缩进语法
  • 统一类定义
  • 统一字符编码类型
  • 统一导入模块的路径搜索方式
  • 修正列表推导式的变量作用域泄露
  • 修正非法比较操作异常
  • 统一抛出异常语法
  • 统一异常处理语法
  • 统一输入函数
  • 统一输出函数
  • 统一文件操作函数
  • 统一列表迭代器生成函数
  • 统一迭代器迭代函数

前言

最近 Python 之父 Guido van Rossum 终于在 Python 官方邮件组落实了 Python 2.7 的终焉之日(EOL)为 2020 年 1 月 1 日,之后不会有任何更新,包括源码的安全补丁。

Let’s not play games with semantics. The way I see the situation for 2.7 is that EOL is January 1st, 2020, and there will be no updates, not even source-only security patches, after that date. Support (from the core devs, the PSF, and python.org) stops completely on that date. If you want support for 2.7 beyond that day you will have to pay a commercial vendor. Of course it’s open source so people are also welcome to fork it. But the core devs have toiled long enough, and the 2020 EOL date (an extension from the originally annouced 2015 EOL!) was announced with sufficient lead time and fanfare that I don’t feel bad about stopping to support it at all.

所以,还没有兼容或移植到 Python 3.x 的程序,或许已经到了该提上日程的时候了。在下文中,我们就 3 个经常在面试中出现的问题来展开。

  1. 选择 Python 2 还是 3 ?
  2. 两者的主要区别是什么?
  3. 如何编写兼容两者的代码?

Python 2 or 3 ?

Python 3 被钦定为 Python 的未来,于 2008 年末发布,是目前正在开发的版本。旨在解决和修正 Python 2 遗留的设计缺陷、清理代码库冗余、追求有且仅有一种最佳实践方式来执行任务等问题。

起初,由于 Python 3 不能向后兼容的事实,导致了用户采用缓慢,对初学者不友好等问题。但在 Python 社区的努力和决绝态度下,截至龟爷发出邮件之前,已经有了 21903 个 Packages 可以支持 Python 3.5,其中包括了绝大多数最受欢迎的封装库,与此同时也有越来越多的封装库(e.g. Django、Numpy)表示其新版本将不再支持 Python 2。

可见时至今日的 Python 3 已成气候,正如龟爷在邮件中所说:「停止支持 Python 2,我完全没觉得有啥糟糕的」。所以笔者认为,如果你喜欢 Python 并希望能够掌握它,那么你完全没有必然去纠结于学习 2 还是 3 的问题。而且当我们在讨论 Python 2.x 的问题时,实际上更多的是在讨论 Python 2.7。

Python 2.7 于 3.0 之后的 2010 年 7 月 3 日发布,计划作为 2.x 的最后一个版本。Python 2.7 的历史任务在于通过提供 2 和 3 之间的兼容性措施,使 Python 2.x 的用户更容易将代码移植到 Python 3.x 上。那么如果你希望自己的代码能够兼容两个不同的版本,首先你起码要让代码能够正常的运行在 Python 2.7 上。

NOTE:下文使用 P2 表示 Python 2.7;使用 P3 表示 Python 3.x。

Python Future 的兼容性

Python Future 顾名思义是为了 “兼容” 而生的 Package/Module,即:把新版本的特性导入到当前版本中,以此在当前版本中使用一些新版本的特性。

future Module

__future__ 是一个 Python build-in 的 Module,该 Module 最主要的作用是支持在 P2 中导入那些在 P3 才生效的模块和函数。

Help on module __future__:NAME__future__ - Record of phased-in incompatible language changes.FILE/usr/lib64/python2.7/__future__.py
特性 在此版本可选 在此版本内置 效果
nested_scopes 2.1.0b1 2.2 PEP 227:静态嵌套作用域
generators 2.2.0a1 2.3 PEP 255:简单生成器
division 2.2.0a2 3.0 PEP 238:除法操作符改动
absolute_import 2.5.0a1 3.0 PEP 328:Imports 多行导入与绝对相对路径
with_statement 2.5.0a1 2.6 PEP 343:with 语句
print_function 2.6.0a2 3.0 PEP 3105:print 语句升级为函数
unicode_literals 2.6.0a2 3.0 PEP 3112:Bytes 类型

示例 1:在 Python2.x 中使用 Python3 build-in 的 print() 函数。

from __future__ import print_function
print('string', end='')

示例 2:在 Python2.x 中使用 Python3 的 Division(精确除法)。

from __future__ import division
print 1/2

future Package

future 是一个需要额外 pip 安装的 Package,内含了更加丰富的 Sub-package 和 Modules。

Help on package future:NAMEfutureFILE/usr/lib/python2.7/site-packages/future/__init__.py

统一不等于语法

P2 支持使用 <>!= 表示不等于。

P3 仅支持使用 != 表示不等于。

兼容技巧:统一使用 != 语法

统一整数类型

P2 中整数类型可以细分为短整型 int 和长整型 long。

P3 废除了短整型,并统一使用 int 表示长整型(不再有 L 跟在 repr 后面)。

兼容技巧

# Python 2 only
k = 9223372036854775808L
# Python 2 and 3:
k = 9223372036854775808# Python 2 only
bigint = 1L
# Python 2 and 3
from future.builtins import int
bigint = int(1)

统一整数除法

P2 的除法 / 符号实际上具有两个功能:

  • 当两个操作数均为整型对象时,进行的是地板除(截除小数部分),返回整型对象;
  • 当两个操作数存在至少一个浮点型对象时,进行的是真除(保留小数部分),返回浮点型对象。

P3 的除法 / 符号仅仅具有真除的功能,而地板除的功能则交由 // 来完成。

兼容技巧

# Python 2 only:
assert 2 / 3 == 0
# Python 2 and 3:
assert 2 // 3 == 0
“True division” (float division):# Python 3 only:
assert 3 / 2 == 1.5
# Python 2 and 3:
from __future__ import division    # (at top of module)

统一缩进语法

P2 可以混合使用 tab 和 space 两种方式来进行缩进(1 个 tab == 8 个 space),但实际上这一特性并非所有 IDE 都能够支持,会因此出现同样的代码无法跨 IDE 运行的情况。

P3 统一使用 tab 作为缩进,如果 tab 和 space 同时存在,就会触发异常:

TabError: inconsistent use of tabs and spaces in indentation.

兼容技巧:统一使用 tab 作为缩进。

统一类定义

P2 同时支持新式类(object)和老式类。

P3 则统一使用新式类,并且只有使用新式类才能应用多重继承。

兼容技巧:统一使用新式类。

统一字符编码类型

P2 默认使用 ASCII 字符编码,但因为 ASCII 只支持数百个字符,并不能灵活的满足非英文字符,所以 P2 同时也支持 Unicode 这种更强大的字符编码。不过,由于 P2 同时支持两套字符编码,就难免多出了一些标识和转换的麻烦。

而 P3 统一使用 Unicode 字符编码,这节省了开发者的时间,同时也可以轻松地在程序中输入和显示更多种类的字符。

兼容技巧:在所有的字符串赋值中均使用前缀 u,或引入 unicode_literals 字符模块。

# Python 2 only
s1 = 'The Zen of Python'
s2 = u'きたないのよりきれいな方がいい\n'# Python 2 and 3
s1 = u'The Zen of Python'
s2 = u'きたないのよりきれいな方がいい\n'# Python 2 and 3
from __future__ import unicode_literals    # at top of modules1 = 'The Zen of Python'
s2 = 'きたないのよりきれいな方がいい\n'

统一导入模块的路径搜索方式

P2 导入一个模块时首先会搜索当前目录(cwd),若非,则搜索环境变量路径(sys.path)。这一特性时常给开发者带来困扰,相信大家都曾经碰到过,尤其当自定义模块与系统模块重名的时候;

为了解决这个问题,默认的 P3 仅会搜索环境变量路径,当你需要搜索自定义模块时,你可以在包管理模式下将项目路径加入到环境变量中,然后再使用绝对路径和相对路径(以 . 开头)的方式来导入。

兼容技巧:统一使用绝对路径进行自定义模块导入。

修正列表推导式的变量作用域泄露

P2 的列表推倒式中的变量会泄露到全局作用域,例如:

import platformprint('Python', platform.python_version())
i = 1
print('before: I = %s' % i)
print('comprehension: %s' % [i for i in range(5)])
print('after: I = %s' % i)# OUT
Python 2.7.6
before: i = 1
comprehension: [0, 1, 2, 3, 4]
after: i = 4

P3 则解决了这个问题,列表推倒式中的变量不再泄露到全局作用域。

import platformprint('Python', platform.python_version())
i = 1
print('before: i =', i)
print('comprehension:', [i for i in range(5)])
print('after: i =', i)# OUT
Python 3.4.1
before: i = 1
comprehension: [0, 1, 2, 3, 4]
after: i = 1

修正非法比较操作异常

P2 能够对两个数据类型并不相同的对象进行比较。

import platformprint('Python', platform.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))# OUT
Python 2.7.6
[1, 2] > 'foo' = False
(1, 2) > 'foo' = True
[1, 2] > (1, 2) = False

不过,这种看似方便的特性,实际上却是一个定时炸弹,因为你无法唯一的确定到底是什么原因导致的返回值为 False(可能是数据比较、也可能是数据类型不一致)。

P3 则对其进行了修正,如果比较操作数类型不一致时,会触发 TypeError 异常。

兼容技巧:永远不要比较数据类型不一致的对象。

统一抛出异常语法

P2 同时支持新旧两种异常触发语法:

raise IOError, "file error"   # Old
raise IOError("file error")   # New

P3 则统一使用新异常触发语法,否则会触发 SyntaxError 异常:

raise IOError("file error")

兼容技巧

### 抛出异常
# Python 2 only:
raise ValueError, "dodgy value"
# Python 2 and 3:
raise ValueError("dodgy value")### 使用 traceback 抛出异常
# Python 2 only:
traceback = sys.exc_info()[2]
raise ValueError, "dodgy value", traceback
# Python 3 only:
raise ValueError("dodgy value").with_traceback()
# Python 2 and 3: option 1
from six import reraise as raise_
# or # from future.utils import raise_
traceback = sys.exc_info()[2]
raise_(ValueError, "dodgy value", traceback)
# Python 2 and 3: option 2
from future.utils import raise_with_traceback
raise_with_traceback(ValueError("dodgy value"))### 异常链处理
# Setup:
class DatabaseError(Exception):pass
# Python 3 only
class FileDatabase:def __init__(self, filename):try:self.file = open(filename)except IOError as exc:raise DatabaseError('failed to open') from exc
# Python 2 and 3:
from future.utils import raise_from
class FileDatabase:def __init__(self, filename):try:self.file = open(filename)except IOError as exc:raise_from(DatabaseError('failed to open'), exc)

统一异常处理语法

P2 实现异常处理也能够支持两种语法。

try:let_us_cause_a_NameError
except NameError, err:
# except NameError as err:print err, '--> our error message'

P3 的异常处理则强制要求使用 as 关键字的方式。

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

兼容技巧:统一使用 as 关键字的异常处理方式。

统一输入函数

P2 支持 raw_input 和 input 两个输入函数,区别在于前者仅能返回 String 类型对象,后者则支持返回数字和字符串两种数据类型对象,并且当输入为表达式时,会隐式调用 eval 函数返回其执行结果。显然的,使用 input 是更加灵活的写法。

所以 P3 统一的使用了 input 函数进行输入处理。

兼容技巧:统一使用 input 内置函数。

# Python 2 only:
input("Type something safe please: ")# Python 2 and 3
from future.builtins import input
eval(input("Type something safe please: "))

统一输出函数

P2 中的 print 即是关键字又是内置函数。print 'Hello world!' 为一条语句,print('Hello world!') 则为一次函数调用。

P3 统一使用 print 函数进行输出操作,其原型如下,这一改变让 P3 的输出处理变得更加简洁、强大而优雅,通过实参的传递就能替代 P2 中繁复的代码实现。

print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False)

兼容技巧

### 单行打印单个 String
# Python 2 only:
print 'Hello'
# Python 2 only:
print 'Hello'### 单行打印多个 String
# Python 2 only:
print 'Hello', 'Guido'
# Python 2 and 3:
from __future__ import print_function    # (at top of module)
print('Hello', 'Guido')### 输出重定向
# Python 2 only:
print >> sys.stderr, 'Hello'
# Python 2 and 3:
from __future__ import print_function
print('Hello', file=sys.stderr)### 换行打印
# Python 2 only:
print 'Hello',
# Python 2 and 3:
from __future__ import print_function
print('Hello', end='')

统一文件操作函数

P2 支持使用 file 和 open 两个函数来进行文件操作。

P3 则统一使用 open 来进行文件操作。

兼容技巧:统一使用 open 函数。

# Python 2 only:
f = file(pathname)
# Python 2 and 3:
f = open(pathname)

统一列表迭代器生成函数

P2 支持使用 range 和 xrange 两个函数来生成可迭代对象,区别在于前者返回的是一个列表类型对象,后者返回的是一个类似生成器(惰性求值)的迭代对象,支持无限迭代。所以当你需要生成一个很大的序列时,推荐使用 xrange,因为它不会一上来就索取序列所需的所有内存空间。如果只对序列进行读操作的话,xrange 方法效率显然会更高,但是如果要修改序列的元素,或者往序列增删元素的话,那只能通过 range 方法生成一个 list 对象了。

P3 则统一使用 range 函数来生成可迭代对象,但其实 P3 的 range 更像是 P2 的 xrange。所以在 P3 中如果你想得到一个可以被修改的列表对象,你需要这么做:

list(range(1,10))
[1, 2, 3, 4, 5, 6, 7, 8, 9]

兼容技巧:统一使用 range 函数

# Python 2 only:
for i in xrange(10**8):...# Python 2 and 3: forward-compatible
from future.builtins import range
for i in range(10**8):...# Python 2 and 3: backward-compatible
from past.builtins import xrange
for i in xrange(10**8):...

统一迭代器迭代函数

P2 中支持使用内置函数 next 和迭代器对象的 .next() 实例方法这两种方式来获取迭代器对象的下一个元素。所以,在实现自定义迭代器对象类时,必须实现 .next() 实例方法:

# Python 2 only
class Upper(object):def __init__(self, iterable):self._iter = iter(iterable)def next(self):          # Py2-styface iterator interfacereturn self._iter.next().upper()def __iter__(self):return selfitr = Upper('hello')
assert itr.next() == 'H'     # Py2-style
assert list(itr) == list('ELLO')

但在 P3 中统一了使用 next 内置函数来获取下一个元素,如果试图调用 .next() 方法则会触发 AttributeError 异常。所以,在 P3 中实现自定义迭代器所要实现的是 __next__ 特殊方法。

兼容技巧

# Python 2 and 3: option 1
from future.builtins import objectclass Upper(object):def __init__(self, iterable):self._iter = iter(iterable)def __next__(self):      # Py3-style iterator interfacereturn next(self._iter).upper()  # builtin next() function callsdef __iter__(self):return selfitr = Upper('hello')
assert next(itr) == 'H'      # compatible style
assert list(itr) == list('ELLO')# Python 2 and 3: option 2
from future.utils import implements_iterator@implements_iterator
class Upper(object):def __init__(self, iterable):self._iter = iter(iterable)def __next__(self):                  # Py3-style iterator interfacereturn next(self._iter).upper()  # builtin next() function callsdef __iter__(self):return selfitr = Upper('hello')
assert next(itr) == 'H'
assert list(itr) == list('ELLO')

Python 2 和 3 的区别及兼容技巧相关推荐

  1. python3兼容python2 print_python 字符串 r raw Python2 和 Python3 的区别及兼容技巧

    前言 最近 Python 之父 Guido van Rossum(龟爷)终于在 Python 官方邮件组落实了 Python 2.7 的终焉之日(EOL). 说的是 Python 2.7 的 EOL ...

  2. python是什么类型的编程语言-python和scratch有什么区别

    python和scratch有什么区别 发布时间:2020-08-24 10:16:05 来源:亿速云 阅读:200 python和scratch有什么区别?针对这个问题,这篇文章详细介绍了相对应的分 ...

  3. python3各版本区别-Python各版本之间的区别

    Python各版本之间的区别 发布时间:2020-06-17 14:22:08 来源:亿速云 阅读:148 作者:鸽子 Python发展至今有哪些版本和各版本的区别是: 一.系统区别: 1.Downl ...

  4. python post与get的区别_python中get和post有什么区别

    更多编程教程请到:菜鸟教程 https://www.piaodoo.com/ 友情链接: 高州阳光论坛https://www.hnthzk.com/ 人人影视http://www.sfkyty.com ...

  5. python 多进程_说说Python多线程与多进程的区别?

    公众号新增加了一个栏目,就是每天给大家解答一道Python常见的面试题,反正每天不贪多,一天一题,正好合适,只希望这个面试栏目,给那些正在准备面试的同学,提供一点点帮助! 小猿会从最基础的面试题开始, ...

  6. php和python区别-什么是Python和php?Python与PHP有什么区别

    Python和php相信会有很多人都不太了解,下面php中文网就带领大家认识一下Python与PHP区别. 一:什么是Python? Python是一种高级面向对象的编程语言.Python具有内置的数 ...

  7. java和python的web自动化有什么区别-Java Web开发和Python Web开发之间的区别

    今天的文章讨论了Java Web开发和Python Web开发之间的区别.我不鼓励我们在这里从Java Web迁移到Python Web开发.我只是想谈谈我的感受.它不一定适合所有情况,仅供我们参考. ...

  8. Python列表,元组,字典的区别

    Python列表,元组,字典的区别: 1.元组是不可变的, 而列表.字典是可变的.元组是不可变对象,对象一旦生成,它的值将不能更改:列表是可变对象,对象生成后,可以对其元素进行更改.添加.删除.清空. ...

  9. 【Python面试】谈谈对 Python 和其他语言的区别?​

    最近公众号新增加了一个栏目,就是每天给大家解答一道Python常见的面试题,反正每天不贪多,一天一题,正好合适,只希望这个面试栏目,给那些正在准备面试的同学,提供一点点帮助! 小猿会从最基础的面试题开 ...

最新文章

  1. Linux学习(3)-常用命令
  2. matlab第四章例题,第四章课后作业matlab验证
  3. MetaSploit攻击实例讲解------攻击445端口漏洞(kali linux 2016.2(rolling))(详细)
  4. Python Virtualenv Anaconda
  5. 解决SVN:E210007无法协商认证机制
  6. 把经典的ABAP webdynpro应用配置到SAP Fiori Launchpad里
  7. why always WebContent is added as prefix of url when repository request served
  8. json java的set函数,JsonConfig的jsonConfig.setExcludes的用法
  9. 将编号为0和1的两个栈存放于一个数组空间V[m]中。
  10. 要怎么样做一个合格点的程序猿呢?
  11. python习题错误整理(一)
  12. 微信小程序学习笔记-(11)-仿糗事百科
  13. SpringBoot+RabbitMQ 实现 RPC 调用
  14. Servlet的Mapping
  15. ROMS四维变分测试
  16. Cotherm 多物理场耦合方案
  17. 《视觉SLAM十四讲》读书笔记(四)
  18. 寻找 JAVA 控件,彗都控件网\中国控件网(http://***)http://www.componentcn.com/
  19. 安装Kali Linux渗透系统
  20. 英语笔记1.2.2022

热门文章

  1. c java 开发android_java代码与纯C代码混编完成android应用的开发
  2. python 最小硬币数_程序以找到要在Python中达到目标的硬币组合数量
  3. plt转pdf软件_无须转Word也能轻松编辑PDF的软件,它来了!
  4. cordova 不安全 css,[译] CSS Flexbox 中安全/不安全的对齐方式
  5. 量子力学考研等待计算机吗,考研《量子力学》专业课满分经验谈
  6. 我们学习效率为什么这么低?CMU和PITT的科学家利用BCI技术对此做了相关研究
  7. Nilearn教程系列(2)-3D和4D niimgs:处理和可视化
  8. 西南这座城,脸,比北上广还有用
  9. 科学院和工程院公布188名新院士!外籍占比26%,中科院北大清华38人,阿里王坚当选...
  10. HDU-2089-不要62