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 Constructicons

What is actually happening in this call to a classmethod?

This is the code used in the video:

class Book:
    def __init__(self, title, author):
        self.title = title
        self.author = author

    def __str__(self):
        return '{} by {}'.format(self.title, self.author)

class Bookcase:
    def __init__(self, books=None): # does this not overwrite the list passed in and set it to None??
        self.books = books

    @classmethod
    def create_bookcase(cls, book_list):
        books = []
        for title, author in book_list:
            books.append(Book(title, author))
        return cls(books)

bc = Bookcase.create_bookcase([('Moby-Dick', 'Herman Melville'), ('Jungle Book', 'Rudyard Kipling')])

From what I can tell, this is what's happening when the command at the bottom is called:

  1. A list with 2 books (tuples of strings representing the book's title and author) is sent into create_bookcase.
  2. An empty list called 'books' is created.
  3. For each book that was sent in, the title and author is sent to the class 'Book', creating an instance with attributes 'title' and 'author', and a str() method, then
  4. That Book instance is then appended to the empty list 'books' that was created.
  5. Once the loop has finished and both Book instances are added to the 'books' list, the list is sent to the class 'Bookcase', creating an instance with the attribute 'books' that points to that list of Book instances.

Can anyone add any steps or let me know if I've got something wrong? Perhaps write the step-by-step a little better to help me understand?

Also, what's happening with the books=None part?

1 Answer

Jeff Muday
MOD
Jeff Muday
Treehouse Moderator 26,998 Points

I like that you are thinking through this logically. It's a great way to understand class methods. You identified every step correctly. To be better compliant with Python3, I would replace the __str__ method with a __repr__ method since it will allow you to directly print the representation of the object.

Class methods allow you to use methods that belong to a class without "directly" instantiating a class object.

In particular, Bookcase.create_bookcase() is a method that can be thought of as a "Factory" method that creates a Bookcase object that is pre-populated with Books. Each Book object that is placed in the Bookcase comes from a list of title and author tuples that was passed to the class method. At the line where return is located, the cls(books) is calling the Bookcase.__init__(books) method to instantiate and return the new Bookcase.

The None object that is given as a default parameter on the __init__ method is sort of like a placeholder for an empty list of books. If no parameters are given to __init__ then it is assumed the Bookcase is empty. You can skip the books=None if you are using Python 3.x. But it is a good practice to be able to instantiate an object without parameters.

class Book:
    def __init__(self, title, author):
        self.title = title
        self.author = author

    def __repr__(self):
        return '{} by {}'.format(self.title, self.author)

class Bookcase:
    def __init__(self, books=None):
        self.books = books

    @classmethod
    def create_bookcase(cls, book_list):
        books = []
        for title, author in book_list:
            books.append(Book(title, author))
        return cls(books)

    def __repr__(self):
        """return a string representation of the list of books in the case"""
        return str(self.books)

bc = Bookcase.create_bookcase([('Moby-Dick', 'Herman Melville'), ('Jungle Book', 'Rudyard Kipling')])
print(bc)

Brill, cheers pal! Pretty sure I get it now :) I'll look into repr now, thanks!