2014-09-01 57 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__通常會不安全?切片端點隱形截斷

無論如何,我可以做任何我需要的東西__getitem__,我只是想知道爲什麼__getslice__顯然被打破。

編輯: CPython中的哪些代碼會截斷片段?這是Python(語言)規範的一部分還是僅僅是cpython(實現)的「特性」?

+0

不得不說:「爲什麼是的,我想2^64片這種馬鈴薯精的」。雖然真的,我真的希望我有一個答案 – inspectorG4dget 2014-09-01 01:29:19

+1

這是一個切片..它會發生在像'maxint-2:maxint + 2'這樣的小切片上:) – wim 2014-09-01 10:27:12

回答

6

Python的C代碼,處理切片適用於實現了sq_slice,經Py_ssize_t(== sys.maxsize)不能處理任何整數對象。 sq_slice插槽是__getslice__特殊方法的C-API等效項。

對於兩元素切片,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 documentationsimple_slicingextended_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 2014-09-01 15:18:44

+0

@wim:此處模糊;我會說這是一個實施限制。 – 2014-09-01 15:21:11

+2

@wim:更新爲引用此文檔;它看起來是一個語言問題,而不是實現細節。 – 2014-09-01 15:45:01