Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

Python Object-Oriented Python Advanced Objects Frustration

Why doesn't super().__len__() take any arguments?

class Liar(list):
    def __len__(self):
      return super().__len__() + 4

I was surprised to find that this was correct. Help me parse what I'm doing into english... I'm extending the list class by creating a list subclass called Liar. It takes a list as an argument. I gave the Liar class a magic len method. It takes an instance of itself (a kind of list) as an argument and returns the length of itself (as defined by the list class's magic len method) plus four.

Am I saying everything right there?

And why doesn't super().len() need an instance passed to it? Isn't it just a method that thinks it's about to be passed something? Why isn't it super().len(self)??

Thanks

1 Answer

Jeff Muday
MOD
Jeff Muday
Treehouse Moderator 28,716 Points
  1. the len(x) method of Python is a common way to find the length of an object's data store. The len() method calls the magic "dunder method" __len__() of the object which reports an integer length.

  2. The Liar class inherits ALL the methods of the Python list, but we override only the __len__() method. To accomplish our goal for the Liar class we need to know what the length of the data contained in the Liar object and then "misreport" the value. So the super().__len__() calls the inherited code which returns the list length and to that we simply add on an offset. So the object "lies" about its length.

  3. You are insightful in thinking there are other ways to do this! We have to be careful that we don't create a recursive call when we use Python's len() method-- calling len(self) will cause a runtime error because the object recursively calls itself. So it involves MAKING A COPY of the object avoids this problem-- we make a copy by calling self[:] and reporting its len(self[:]) value

class Liar(list):
    def __len__(self):
        # call the inherited __len__() + 4
        return super().__len__() + 4

class Liar2(list):
    def __len__(self):
        # return the length of a COPY of the list + 3
        return len(self[:]) + 3


x = Liar([1,2,3])
y = Liar2([1,2,3])

print('x =',x)
print('type of x =', type(x))
print('len(x) =', len(x))

print('y=',y)
print('type of y =', type(y))
print('len(y) =', len(y))

Here are the results:

x = [1, 2, 3]
type of x = <class '__main__.Liar'>
len(x) = 7
y= [1, 2, 3]
type of y = <class '__main__.Liar2'>
len(y) = 6