2014-09-01 2 views
5
>>> 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 

Почему вызов getslice не уважает stop я послал в, вместо того, чтобы молча подставляя 2^63 - 1? Означает ли это, что реализация __getslice__ для вашего синтаксиса, как правило, будет небезопасной с длинными?Slice оконечные незримо усечен

Я могу делать все, что мне нужно, с __getitem__ в любом случае, мне просто интересно, почему __getslice__, по-видимому, сломан.

Редактировать: Где код в CPython, который обрезает срез? Является ли эта часть спецификации python (language) или просто «функцией» cpython (реализация)?

+0

Должен сказать: «почему да, я хотел бы 2^64 ломтиков этого прекрасного картофеля». Серьезно, хотя, мне очень жаль, что у меня не было ответа – inspectorG4dget

+1

Это один кусочек .. и это будет так же, как и с меньшим фрагментом, например 'maxint-2: maxint + 2' :) – wim

ответ

6

Питон C код, который обрабатывает нарезка для объектов, которые реализуют sq_slice слот, не может обрабатывать любые целые числа над Py_ssize_t (== sys.maxsize). Слот sq_slice представляет собой эквивалент C-API специального метода __getslice__.

Для двухэлементного среза Python 2 использует один из SLICE+* opcodes; затем обрабатывается apply_slice() function. Это использует _PyEval_SliceIndex function для преобразования индексных объектов Python (int, long или чего-либо, реализующего __index__ method) в целое число 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. 
*/ 

Это означает, что любой нарезка в Python 2 с использованием синтаксиса 2-значения ограничивается значениями в диапазоне sys.maxsize при условии слота sq_slice.

нарезка, используя форму на три значения (item[start:stop:stride]) использует вместо BUILD_SLICE opcode (с последующим BINARY_SUBSCR), и это создает вместо slice() object без ограничения, чтобы sys.maxsize.

Если объект не реализует sq_slice() слота (поэтому нет __getslice__ не присутствует) функция apply_slice() также падает обратно с использованием slice() объекта.

Что касается этой детали реализации или ее части: Slicings expression documentation различает simple_slicing и extended_slicing; первая только разрешает форму short_slice. Для простого нарезания индексы должны быть простые целые числа:

Нижняя и верхняя граница выражения, если таковые имеются, должны вычисляться простых чисел; значения по умолчанию равны нулю и sys.maxint, соответственно.

Это предполагает что Python 2 язык ограничивает индексы для sys.maxint значений, запрещая длинные целые числа. В Python 3 простой срез был вырезан из всего языка.

Если ваш код должен поддерживать нарезку со значениями за sys.maxsizeи вы должны наследовать от типа, который реализует __getslice__ тогда ваши варианты для:

  • использовать синтаксис в три-значение, с None для шага:

    Potato()[123:x:None] 
    
  • создать slice() объекты в явном виде:

slice() объекты могут обрабатывать long целые просто отлично; однако slice.indices() method не может справиться с длиной более 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 
+0

Спасибо. Можете ли вы прокомментировать, является ли это языком или реализацией? – wim

+0

@wim: линия размыта; Я бы сказал, что это предел реализации. –

+2

@wim: обновлено, чтобы процитировать документацию по этому поводу; здесь речь идет о языковой проблеме, а не о деталях реализации. –

Смежные вопросы