pixelou
pixelou

Reputation: 804

using __setitem__ requires to also implement __len__ in python 2

This very simple snippet fails on python 2 but passes with python 3:

class A:
    def __init__(self, value):
        self.value = value

    def __setitem__(self, key, value):
        pass

r = A(1)
r[80:-10] = list(range(10))

On python2, the interpreter make a call to __len__ which does not exist and therefore fails with:

Traceback (most recent call last):
  File "prog.py", line 9, in <module>
AttributeError: A instance has no attribute '__len__'

Where is this behaviour documented? It doesn't make sense to force a container to have a size.

Upvotes: 6

Views: 100

Answers (2)

user2357112
user2357112

Reputation: 281683

That's an old-style class quirk. Old-style classes have a lot of poorly-documented quirks, mostly old behavior that hasn't kept up with changes to Python.

Here, types.InstanceType has a __setslice__, which is responsible for looking up the old-style class __setitem__ and __setslice__. Since this __setslice__ exists, Python tries to go through __setslice__, which requires a len call first for negative slice indexes. Your (old-style) class doesn't have __len__, so the call fails.

Use a new-style class:

class A(object):
    ...

Upvotes: 6

FHTMitchell
FHTMitchell

Reputation: 12156

The reason is you're using an old-style class. In python 2 the syntax for a new-style class (which are the only kind of classes in python 3) is

class T(object):
    ...

Upvotes: 0

Related Questions