It is also possible to define variables that are part of the class definition itself. Such variables are called class attributes. For example, let's add a variable that represent the count of all books that have been created.


class Book:
    number_of_books = 0

    def __init__(self, genre, title, author, publication_year):
        self.genre = genre
        self.title = title
        self.author = author
        self.publication_year = publication_year
        Book.number_of_books = Book.number_of_books + 1

    def calculate_age(self):
        return 2023 - self.publication_year
          

For example, if we run the code below, we'll see the number 3 get printed, since there have been 3 books created by the time the code finishes running.


hunger_games = Book('Dystopian fiction', 'The Hunger Games', 'Suzanne Collins', 2008)
ranger_games = Book('Crime Nonfiction', 'Ranger Games', 'Ben Blum', 2017)
strange_book = Book("Cooking", "How to Cook Water", "Yaxson Mang", 2016)
print(Book.number_of_books)
          

Try running the code at Python tutor at this link.

As usual, I have a few notes:

  1. Technically, you can refer to class attributes using the name of an instance. For example, we could ask for ranger_games.number_of_books. However, this is bad style. I strongly advise against accessing class attributes with instance names. This leads to confusing code. Only use class names when accessing or modifying class attributes, e.g. Book.number_of_books.
  2. Technically, you can add an instance attribute with the same name as a class attribute. This is also bad coding style. For example, see what happens when you run the code at this link. You'll see the ranger_games object has a new variable that is ALSO called number_of_books which "hides" the class attribute. Do not do this in real code. The exact details of what happens when you are foolish enough to create instance attributes with the same name as class attributes will not be tested on exams. It's not worth your time to learn.
  3. Class attributes should be used VERY SPARINGLY. The example above is a reasonable example: For some reason you want to count the number of books instantiated. There's no way to do this as an instance attribute since every instance has its own variable, so we use a class attribute instead. Another common example is when there is a constant used by a class, e.g. Math has a class attribute called pi, which you can access with Math.pi. In CS10, you should NEVER use class attributes unless we specifically tell you to or you have a really good reason (e.g. constants or counting the number of somethings across a large number of instances).
  4. This is beyond the scope of the course, but occasionally online you will see someone suggest that class attributes can be used to represent a default value for an instance attribute. This is almost always bad practice. (In case you're curious why, it's because class attributes are mutable).