super not behaving as I expected

Peter Otten __peter__ at web.de
Sun Mar 29 10:49:03 EDT 2020


Antoon Pardon wrote:

> 
> I have the following program
> 
> class slt:
> __slots__ = ()
> 
> def getslots(self):
> print("### slots =", self.__slots__)
> if self.__slots__ == ():
> return []
> else:
> ls = super().getslots()
> ls.extend(self.__slots__)
> return ls
> 
> def __str__(self):
> ls = []
> attrs = self.getslots()
> for attr in attrs:
> ls.append(str(getattr( self, attr)))
> return '->'.join(ls)
> 
> 
> class slt1 (slt):
> __slots__ = 'fld1', 'fld2'
> 
> def __init__(self, vl1, vl2):
> self.fld1 = vl1
> self.fld2 = vl2
> 
> class slt2(slt1):
> __slots__ = 'fld3',
> 
> def __init__(self, vl1, vl2, vl3):
> self.fld1 = vl1
> self.fld2 = vl2
> self.fld3 = vl3
> 
> rc1 = slt1(4, 7)
> rc2 = slt2(11, 18, 29)
> 
> print(rc1)
> print(rc2)
> 
> When I call this I would expect to see the following:
> 
> ### slots = ('fld1', 'fld2')
> ### slots = ()
> 4->7
> ### slots = (fld3,)
> ### slots = ('fld1', 'fld2')
> ### slots = ()
> 11->18->29
> 
> What I actually get is:
> 
> ### slots = ('fld1', 'fld2')
> Traceback (most recent call last):
>   File "slottest", line 39, in <module>
>     print(rc1)
>   File "slottest", line 15, in __str__
>     attrs = self.getslots()
>   File "slottest", line 9, in getslots
>     ls = super().getslots()
> AttributeError: 'super' object has no attribute 'getslots'
> 

Well...

super().method

looks up method in the parent class of the class where it's used -- in your 
case the parent class of slt, or object.

self.attribute

looks up the attribute in the instance, and if that fails works its way up 
the inheritance tree follong the mro; here it succeeds in slt1. This leeds 
to execution of the else branch in getslots() which in turn tries to invoke 
object.getslots() -- and fails.

That would be the normal behaviour. The __slots__ attribute is special, so 
there may be subtle differences.


Anyway, here's my attempt to collect inherited slots:

    @classmethod
    def get_slots(cls):
        all_slots = set()
        for C in cls.__mro__:
            try:
                slots = C.__slots__
            except AttributeError:
                assert C is object
            else:
                all_slots.update(slots)
        return all_slots




More information about the Python-list mailing list