obj[None:None] slice behavior differs from CPython

Create issue
Issue #2136 new
Anders Kaseorg created an issue
class A:
    def __getitem__(self, slice):
        print '__getitem__(%r)' % slice

A()[:]
# CPython 2.7.10 and PyPy 2.6.0: __getitem__(slice(0, 9223372036854775807, None))

A()[None:None]
# CPython 2.7.10: __getitem__(slice(None, None, None))
# PyPy 2.6.0: __getitem__(slice(0, 9223372036854775807, None))

class B(object):
    def __getitem__(self, slice):
        print '__getitem__(%r)' % slice

B()[:]
# CPython 2.7.10 and PyPy 2.6.0: __getitem__(slice(None, None, None))

B()[None:None]
# CPython 2.7.10 and PyPy 2.6.0: __getitem__(slice(None, None, None))

class C:
    def __getslice__(self, lower, upper):
        print '__getslice__(%r, %r)' % (lower, upper)

    def __getitem__(self, slice):
        print '__getitem__(%r)' % slice

C()[:]
# CPython 2.7.10 and PyPy 2.6.0: __getslice__(0, 9223372036854775807)

C()[None:None]
# CPython 2.7.10: __getitem__(slice(None, None, None))
# PyPy 2.6.0: __getslice__(0, 9223372036854775807)

class D(object):
    def __getslice__(self, lower, upper):
        print '__getslice__(%r, %r)' % (lower, upper)

    def __getitem__(self, slice):
        print '__getitem__(%r)' % slice

D()[:]
# CPython 2.7.10 and PyPy 2.6.0: __getslice__(0, 9223372036854775807)

D()[None:None]
# CPython 2.7.10: __getitem__(slice(None, None, None))
# PyPy 2.6.0: __getslice__(0, 9223372036854775807)

Similarly for __setitem__/__setslice__ and __delitem__/__delslice__.

Comments (2)

  1. Carl Friedrich Bolz-Tereick

    That is somewhat bizarre behaviour of CPython, because it's really special-casing None here:

    >>> d[1:2]
    __getslice__(1, 2)
    >>> d[1:None]
    __getitem__(slice(1, None, None))
    >>> d[1:]
    __getslice__(1, 9223372036854775807)
    >>> d[None:1]
    __getitem__(slice(None, 1, None))
    

    I am tempted to document this as a difference between CPython and PyPy and leave the behaviour as is.

  2. Anders Kaseorg reporter

    Actually I claim it is PyPy, not CPython, that is special-casing None. In CPython, None has the same behavior as any non-__index__ing object:

    >>> D()[1:None]
    __getitem__(slice(1, None, None))
    >>> D()[1:'foo']
    __getitem__(slice(1, 'foo', None))
    >>> D()[1:(2, 3)]
    __getitem__(slice(1, (2, 3), None))
    

    In PyPy, using any other non-__index__ing object throws an error:

    >>>> D()[1:None]
    __getslice__(1, 9223372036854775807)
    >>>> D()[1:'foo']
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: 'str' object cannot be interpreted as an index
    >>>> D()[1:(2, 3)]
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: 'tuple' object cannot be interpreted as an index
    
  3. Log in to comment