Python3的range比Python2的xrange功能更强大

如果你在Python2和Python3之间切换使用,你可能会认为Python2中的xrange和Python3中的range功能是一样的。看起来仅仅是把xrange更名为range罢了,是吗?

但是情况并非如此。

与Python3的range相比,Python2的xrange有点受到限制了。本文将探究Python2中的xrange和Python3中的range之间的差异。

写作本文的灵感来自去年在每周Pyhon会谈中对range对象提出的一个问题。

Python2 vs Python3: range

首先需要来说明下range在Python2和Python3中分别是如何工作的。

在Python2中,range函数返回一个整数列表:

xrange类代表的是一个迭代器,对其遍历可获得同样的结果。但是它是惰性的:

Python3中也存在这种惰性。在Python3中,原先的range函数被移除掉了,并将xrange更名为range:

所以,若你想要在Pyhon3中实现类似Python2中的range的功能,就必须将range对象转化为一个列表:

好吧,现在让我们来比较Python2中的xrange类和Python3中的range类。

相似性

在探究xrange和range对象之间的差异之前,让我们先看一看两者之间的相似性。

Python2中的xrange具有描述性字符串表示形式:

Python3中的range对象同样如此:

Python2中的xrange对象是一个迭代器(任何可遍历的事物称为迭代器):

Python3中的range对象也是迭代器:

xrange对象有起点、终点和步长。步长和起点都是可选择的:

range对象也是如此:

两者都有长度,并且都可进行正序或者倒序索引:

Python将range和xranges都视为序列:

xrange和range在基本功能方面存在许多相似性。接下来,让我们谈论两者之间的区别。

双下标方法

第一个不同之处是Python2的xrange和Python3的range的内置文档。

如果使用help函数请求xrange文档,我们将会看到许多双下标方法。在Python中使用双下标方法对对象进行运算符操作(像+或者*),同样也可对不同对象间共享的特征进行操作(像len和str函数)。

以下为Python2中的xrange对象实现的核心双下标方法:

以下为Python3中的range对象实现的核心双下标方法:

注意,range对象要比xrange支持更多的操作运算符。让我们看一下其中的一些。

可比性

Python3中的range支持相等性检查:

python2中的xrange对象看起来也支持相等性检查:

但是,实际上采用的是Python默认的一致性检查:

两个xrange对象将不会被视为相等的,除非它们实际上是同一个对象。

但是,在Python3中对两个range对象进行比较时,实际上是检查每个对象的起点、终点和步长是否相同:

切片

我们已经看到Python2中的xrange和Python3中的range都支持索引:

Python3中的range对象也支持切片:

但是,xrange却不支持切片:

包含性

range和xrange都支持包含性检查:

但是,xrange对此的支持是有迷惑性的。实际上,Python2中的xrange对象没有实现__contains__方法,而此方法是用来实现Python中的in操作符的。

所以,当我们请求一个xrange对象是否包含一个数字时,为了得到结果,Python会对xrange对象进行遍历,直到找到相应的匹配值。

这在我的电脑上的Python 2.7.12 中运行时大约耗时20s:

但是,在Python3中运行时可立刻返回结果:

Python3能够立刻返回range对象的结果,因为结果是基于提供的起点、终点和步长计算而得到的。

起点、终点和步长

在Python3中,range对象有起点、终点和步长:

这些在运用或者扩展range的性能方面是有用的。

例如:我们可能希望对range对象进行取反,得到range对象在数轴相反方向上的镜像。

虽然range对象不支持此功能,但我们可以通过对起点、终点和步长进行取反实现相似的功能,创建一个新的range对象:

虽然,起点、终点和步长可作为Python2中的xrange对象的参数,但是xrange对象并不具备这些属性:

如果你想要得到xrange对象的起点、终点和步长,你需要手动对其进行计算。像这样的代码可能会起作用:

支持大数

这是不实用的最后一点区别。但是,对于range和xrange的一些趣味性使用案例可能是重要的。

Python3中的range对象可接受任何大小的整数:

但是,Python2中的xrange对象受限于接受的整数大小:

我经常会在现场团队教学环节碰到这种区别,因为在授课时,我有时会使用含有大数这样的不实用的例子。

这些重要吗?

很多时候,你在使用Python2中的xrange对象或是Python3中的range对象时,可能只是创建它们并立刻进行遍历:

所以,我前面提到的那些xrange的隐藏功能在大多数时候就显得不那么重要了。

然而,在对一系列连续整数进行诸如切片、快速包含性检查和相等性检查等操作时就显得有用多了。在这些情况下,Python2使用者倾向于使用range函数,返回一个列表。但是在Python3中的range类中,你总会找到你所想要的东西。几乎对于每次要进行的操作,Python3中的range具有速度快,内存节约并且功能强大。

Python3着力确保内置函数节约内存并具有更快的运行速度。许多内置函数(比如:zip,map和filter)现在返回的是迭代器和惰性对象,而不是列表了。

同时,Python3使得一些常见函数,像range等,更富有特性。

相较于Python2,Python3作出了许多较大的改善。但是,也存在升级到Python3时只带来许多微小益处的情况。如果您还没有进行升级,我强烈建议您认真思考下是否有意义将代码升级到Python3版本。

英文原文:http://treyhunner.com/2018/02/python-3-s-range-better-than-python-2-s-xrange/

译者:左风

  • 发表于:
  • 原文链接http://kuaibao.qq.com/s/20180227A069ML00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。

扫码关注云+社区

领取腾讯云代金券