为什么在Python3中,用不同值初始化的范围彼此比较相等?

当我在解释器中执行以下命令时:

>>> r1 = range(0)
>>> r2 = range(2, 2, 2)
>>> r1 == r2
True

结果是True.为什么会这样?为什么具有不同参数值的两个不同对象被视为相等?

推荐答案

The range objects are special:

Python将100个对象与101个对象进行比较.这本质上意味着

startstopstep参数完全不同这一事实在这里没有区别,因为they all represent an empty list when expanded:

例如,前range个对象:

list(range(0))  # []

第二个range个物体:

list(range(2, 2, 2)) # []

Both represent an empty list由于两个空列表的比较相等(True),所以range个对象将对它们进行比较.

因此,你可以拥有完全不同的lookingrange个对象;如果它们代表相同的序列,它们将相等:

range(1, 5, 100) == range(1, 30, 100) 

两者都表示一个列表,其中只有一个元素[1],因此这两个元素的比较也将相等.


No, range objects are really special:

但是,请注意,即使比较没有判断how,它们也代表了一个序列,即使用solely比较can be achievedstartstep以及range个对象中的len的结果;这对比较的速度有着非常有趣的影响:

r0 = range(1, 1000000)    
r1 = range(1, 1000000)

l0 = list(r0)    
l1 = list(r1)

速度极快:

%timeit r0 == r1
The slowest run took 28.82 times longer than the fastest. This could mean that an intermediate result is being cached 
10000000 loops, best of 3: 160 ns per loop

另一方面, list ..

%timeit l0 == l1
10 loops, best of 3: 27.8 ms per loop

是 啊


如前所述,这只适用于Python 3中的range对象.Python 2 range()是一个普通的ol'函数,它返回一个列表,而2.x xrange对象不具备Python 3中range个对象所具有的比较能力(102).

请看100,直接从Python 3 range对象的源代码中获取引号.其中记录了两个不同范围之间的比较实际需要的内容:简单快速的操作.range_equals功能在102中用于EQNE种情况,并分配给103.

我相信range_equals的实现非常可读(因为它非常简单):

/* r0 and r1 are pointers to rangeobjects */

/* Check if pointers point to same object, example:    
       >>> r1 = r2 = range(0, 10)
       >>> r1 == r2
   obviously returns True. */
if (r0 == r1)
    return 1;

/* Compare the length of the ranges, if they are equal 
   the checks continue. If they are not, False is returned. */
cmp_result = PyObject_RichCompareBool(r0->length, r1->length, Py_EQ);
/* Return False or error to the caller
       >>> range(0, 10) == range(0, 10, 2)  
   fails here */
if (cmp_result != 1)
    return cmp_result;

/* See if the range has a lenght (non-empty). If the length is 0
   then due to to previous check, the length of the other range is 
   equal to 0. They are equal. */
cmp_result = PyObject_Not(r0->length);
/* Return True or error to the caller. 
       >>> range(0) == range(2, 2, 2)  # True
   (True) gets caught here. Lengths are both zero. */
if (cmp_result != 0)
    return cmp_result;

/* Compare the start values for the ranges, if they don't match
   then we're not dealing with equal ranges. */
cmp_result = PyObject_RichCompareBool(r0->start, r1->start, Py_EQ);
/* Return False or error to the caller. 
   lens are equal, this checks their starting values
       >>> range(0, 10) == range(10, 20)  # False
   Lengths are equal and non-zero, steps don't match.*/
if (cmp_result != 1)
    return cmp_result;

/* Check if the length is equal to 1. 
   If start is the same and length is 1, they represent the same sequence:
       >>> range(0, 10, 10) == range(0, 20, 20)  # True */
one = PyLong_FromLong(1);
if (!one)
    return -1;
cmp_result = PyObject_RichCompareBool(r0->length, one, Py_EQ);
Py_DECREF(one);
/* Return True or error to the caller. */
if (cmp_result != 0)
    return cmp_result;

/* Finally, just compare their steps */
return PyObject_RichCompareBool(r0->step, r1->step, Py_EQ);

我也在这里散布了自己的一些 comments ;请看100中的Python等效项.

Python-3.x相关问答推荐

网站抓取:当我使用Chrome DevTools中的网络选项卡时,找不到正确的URL来提供我想要的数据

Numba编译时间呈指数级增长--可以像C编译器一样配置优化级别吗?

将列表项的极列水平分解为新列

没有这样的命令';角色';-可靠分子

我可以设置树视图层次 struct 按钮吗?

为什么不能用格式字符串 '-' 绘制点?

按字母顺序排序列表 (OrderFilter),条件是值为 '' 的条目位于列表 DRF 的末尾

隐藏Cartopy中高纬度非矩形投影的右侧轴(纬度)标签

GEKKO 在没有不等式的模型中抛出不等式定义错误

如何使用`re.findall`从字符串中提取数据

当我判断另一个 checkButton 时,如何判断两个 python tkinter checkButtons?

Python BeautifulSoup:在 Select 语句中排除其他标签

每个数据行中每个数据帧值的总和

排队多个子进程

在初始化之前禁用`__setattr__`的干净方法

Visual Studio Code 中的 Python 3.x 类型提示

__new__ 方法给出错误 object.__new__() 只接受一个参数(要实例化的类型)

判断 dict.items() 中的成员资格的时间复杂度是多少?

为现有项目创建virtualenv

在动态链接库 Anaconda3\Library\bin\mkl_intel_thread.dll 中找不到序数 242