Constructions

What if we need something more complex than just a custom init or new method?

Constructors, as most classmethods would be considered, are a common sight in other languages. They’re less common in Python but still really useful. I highly recommend playing around with them outside of this course and getting comfortable with them.

As for staticmethods, they’re…weird. A staticmethod is a method that doesn’t require an instance self or a class cls. So they belong to a class because, logically, they belong there. Most of the time, though, you’re better served by just creating a function in the same module as your class.

So, would it be possible to do create_bookcase without it being a classmethod? Yes and no. We could write the exact same method with a few differences, like using self instead of cls, and then leave off the decorator. We’d have to create an instance of the class first, though. It’d look something like this:

def create_bookcase(self, book_list):
    for author, title in book_list:
        self.append(Book(author, title))
    return self

We could leave off that last line, too, but it’s generally a best practice to always have functions and methods return. Our use of it becomes a little weird to write out, though.

>>> Bookcase().create_bookcase([("Eric Matthes", "Crash Course Python")])

We have to create the instance first, with Bookcase() and then call the method. By using a class method, we move the instance creation into the method where it makes more sense. It’s a small and fairly subtle design decision but it makes for a nicer interaction in the end.


Example: Bookcase of Books

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):
    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)

Testing

>>> bc = Bookcase.create_bookcase([('Title1','Author1'), ('Title2','Author2')])
>>> bc
<books.Bookcase object at 0x7f565ac0>
>>> str(bc.books[0])
'Title1 by Author1'