切片端点不可见地被截断

wim*_*wim 6 python cpython python-2.7

>>> class Potato(object):
...    def __getslice__(self, start, stop):
...       print start, stop
...         
>>> sys.maxint
9223372036854775807
>>> x = sys.maxint + 69
>>> print x
9223372036854775876
>>> Potato()[123:x]
123 9223372036854775807
Run Code Online (Sandbox Code Playgroud)

为什么对getslice的调用不尊重stop我发送的内容,而是默默地替换2 ^ 63 - 1?这是否意味着__getslice__为您自己的语法实现通常是不安全的长期?

__getitem__无论如何,我可以做任何我需要的事情,我只是想知道为什么__getslice__显然会被打破.

编辑: CPython中截断切片的代码在哪里?这是python(语言)规范的一部分还是cpython(实现)的"特性"?

Mar*_*ers 7

处理实现sq_slice插槽的对象的切片的Python C代码无法处理Py_ssize_t(== sys.maxsize)上的任何整数.该sq_slice槽是的C-API等效__getslice__特殊方法.

对于双元素切片,Python 2使用其中一个SLICE+*操作码 ; 然后由apply_slice()函数处理.这使用_PyEval_SliceIndex函数来Python的索引对象转换(int,long,或任何实施__index__方法)至一个Py_ssize_t整数.该方法有以下注释:

/* Extract a slice index from a PyInt or PyLong or an object with the
   nb_index slot defined, and store in *pi.
   Silently reduce values larger than PY_SSIZE_T_MAX to PY_SSIZE_T_MAX,
   and silently boost values less than -PY_SSIZE_T_MAX-1 to -PY_SSIZE_T_MAX-1.
   Return 0 on error, 1 on success.
*/
Run Code Online (Sandbox Code Playgroud)

这意味着使用2值语法在Python 2中进行的任何切片都限于提供插槽sys.maxsize时范围内的值sq_slice.

使用三值form(item[start:stop:stride])进行切片会改为使用BUILD_SLICE操作码(后跟BINARY_SUBSCR),而是创建一个不限制的slice()对象sys.maxsize.

如果对象没有实现sq_slice()槽(因此不__getslice__存在),则该apply_slice()函数也会回退到使用slice()对象.

至于这是一个实现细节或语言的一部分:Slicings表达文档区分simple_slicingextended_slicing; 前者只允许short_slice表格.对于简单切片,索引必须是普通整数:

下限和上限表达式(如果存在)必须求值为普通整数; 默认值分别为零和sys.maxint.

表明 Python 2 语言将索引限制为sys.maxint值,不允许长整数.在Python 3中,简单的切片已完全从语言中删除.

如果您的代码必须支持使用超出值的切片,sys.maxsize 并且您必须从实现的类型继承,__getslice__那么您的选项是:

slice()对象可以long很好地处理整数; 但是该slice.indices()方法无法处理长度sys.maxsize:

>>> import sys
>>> s = slice(0, sys.maxsize + 1)
>>> s
slice(0, 9223372036854775808L, None)
>>> s.stop
9223372036854775808L
>>> s.indices(sys.maxsize + 2)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
OverflowError: cannot fit 'long' into an index-sized integer
Run Code Online (Sandbox Code Playgroud)

  • @wim:更新引用此文档; 它看起来像是一个语言问题,而不是实现细节. (2认同)