Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 893
pixelou Avatar asked Sep 06 '18 16:09

pixelou


1 Answers

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):
    ...
like image 138
user2357112 supports Monica Avatar answered Oct 14 '22 02:10

user2357112 supports Monica