python3range函数采用迭代器方式的好处_为什么在Python3中“1000000000000000 in range(1000000000000001)”会这么快?...

匿名用户

利用源头,卢克!

在CPython中,range(。。。)。__contains__(一个方法包装器)最终将委托给一个简单的计算,该计算检查值是否可能在范围内。这里速度的原因是我们使用了关于界限的数学推理,而不是范围对象的直接迭代。要解释所使用的逻辑:检查数字是否在开始和停止之间,并且

检查步幅值是否“跨过”我们的数字。

例如,994在范围(4,1000,2)中,因为:4<=994和

(994-4)%2==0。

下面是完整的C代码,由于内存管理和引用计数的细节,代码有点冗长,但基本思想是存在的:static int

range_contains_long(rangeobject *r, PyObject *ob)

{

int cmp1, cmp2, cmp3;

PyObject *tmp1 = NULL;

PyObject *tmp2 = NULL;

PyObject *zero = NULL;

int result = -1;

zero = PyLong_FromLong(0);

if (zero == NULL) /* MemoryError in int(0) */

goto end;

/* Check if the value can possibly be in the range. */

cmp1 = PyObject_RichCompareBool(r->step, zero, Py_GT);

if (cmp1 == -1)

goto end;

if (cmp1 == 1) { /* positive steps: start <= ob < stop */

cmp2 = PyObject_RichCompareBool(r->start, ob, Py_LE);

cmp3 = PyObject_RichCompareBool(ob, r->stop, Py_LT);

}

else { /* negative steps: stop < ob <= start */

cmp2 = PyObject_RichCompareBool(ob, r->start, Py_LE);

cmp3 = PyObject_RichCompareBool(r->stop, ob, Py_LT);

}

if (cmp2 == -1 || cmp3 == -1) /* TypeError */

goto end;

if (cmp2 == 0 || cmp3 == 0) { /* ob outside of range */

result = 0;

goto end;

}

/* Check that the stride does not invalidate ob's membership. */

tmp1 = PyNumber_Subtract(ob, r->start);

if (tmp1 == NULL)

goto end;

tmp2 = PyNumber_Remainder(tmp1, r->step);

if (tmp2 == NULL)

goto end;

/* result = ((int(ob) - start) % step) == 0 */

result = PyObject_RichCompareBool(tmp2, zero, Py_EQ);

end:

Py_XDECREF(tmp1);

Py_XDECREF(tmp2);

Py_XDECREF(zero);

return result;

}

static int

range_contains(rangeobject *r, PyObject *ob)

{

if (PyLong_CheckExact(ob) || PyBool_Check(ob))

return range_contains_long(r, ob);

return (int)_PySequence_IterSearch((PyObject*)r, ob,

PY_ITERSEARCH_CONTAINS);

}

这句话中提到了这个想法的“实质”:/* result = ((int(ob) - start) % step) == 0 */

最后一个注意事项--查看代码段底部的range_contains函数。如果精确类型检查失败,那么我们不会使用所描述的巧妙算法,而是返回到使用_pysequence_itersearch的范围的哑迭代搜索!您可以在解释器中检查这种行为(我这里使用的是V3.5.0):>>> x, r = 1000000000000000, range(1000000000000001)

>>> class MyInt(int):

... pass

...

>>> x_ = MyInt(x)

>>> x in r # calculates immediately :)

True

>>> x_ in r # iterates for ages.. :(

^\Quit (core dumped)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值