Welcome to the Treehouse Community

The Treehouse Community is a meeting place for developers, designers, and programmers of all backgrounds and skill levels to get support. Collaborate here on code errors or bugs that you need feedback on, or asking for an extra set of eyes on your latest project. Join thousands of Treehouse students and alumni in the community today. (Note: Only Treehouse students can comment or ask questions, but non-students are welcome to browse our conversations.)

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and a supportive community. Start your free trial today.

Python Object-Oriented Python Advanced Objects Frustration

Eric Peppler
Eric Peppler
3,600 Points

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 26,998 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