切片索引限制为0x7FFFFFFF

Jon*_*art 8 python python-2.7 python-internals

我正在使用Python(2.7.4)中的切片:

class Foo():
    def __getitem__(self, key):
        # Single value
        if isinstance(key, (int,long)):
            return key

        # Slice
        if isinstance(key, slice):
            print 'key.start = 0x{0:X}   key.stop = 0x{1:X}'.format(key.start, key.stop)
            length = key.stop - key.start
            return str(length)
Run Code Online (Sandbox Code Playgroud)

一切似乎按预期工作:

>>> f = Foo()
>>>
>>> f[42]
42
>>>
>>> f[20:30]
key.start = 0x14   key.stop = 0x1E
'10'
Run Code Online (Sandbox Code Playgroud)

除了切片索引似乎限制为0x7FFFFFFF:

>>> f[0xFEDCBA98 : 0xFFFFFFFF]
key.start = 0x7FFFFFFF   key.stop = 0x7FFFFFFF
'0'
>>> f[0x80000000:0x90000000]
key.start = 0x7FFFFFFF   key.stop = 0x7FFFFFFF
'0'
Run Code Online (Sandbox Code Playgroud)

为什么切片索引不会long与常规int值进行相同的整数提升?这有什么解决方法吗?

Jon*_*art 7

我意识到这似乎是旧式课程的限制.新式类(派生自的类object)的行为符合预期:

class Foo(object):
   #...
Run Code Online (Sandbox Code Playgroud)

结果:

>>> f = Foo()
>>>
>>> f[0x80000000:0x90000000]
key.start = 0x80000000   key.stop = 0x90000000
'268435456'
>>>
>>> f[0xFEDCBA98 : 0x1200000000]
key.start = 0xFEDCBA98   key.stop = 0x1200000000
'73033532776'
>>>
Run Code Online (Sandbox Code Playgroud)

我没有在任何地方看到这个记录.这特别令人困惑,因为这种限制不属于slice班级本身:

>>> s = slice(0xFEDCBA98, 0x1200000000)
>>>
>>> s
slice(4275878552L, 77309411328L, None)
>>>
>>> hex(s.start)
'0xfedcba98L'
Run Code Online (Sandbox Code Playgroud)


the*_*eye 7

经过大量的搜索,我发现了这一点

在python 3.3中,切片的开始和结束都是这样的

start = PyLong_FromSsize_t(istart);
...
end = PyLong_FromSsize_t(istop);
Run Code Online (Sandbox Code Playgroud)

但在2.7中他们被发现是这样的

start = PyInt_FromSsize_t(istart);
...
end = PyInt_FromSsize_t(istop);
Run Code Online (Sandbox Code Playgroud)

在2.7中,PyInt_FromSsize_t最终使用long3.3中PyLong_FromSsize_t的大小,使用大小PyObject.这就是为什么它在3.3而不是在2.7中工作正常.