Get AI summaries of any video or article — Sign up free
Python OOP Tutorial 3: classmethods and staticmethods thumbnail

Python OOP Tutorial 3: classmethods and staticmethods

Corey Schafer·
4 min read

Based on Corey Schafer's video on YouTube. If you like this content, support the original creators by watching, liking and subscribing to their content.

TL;DR

Use `@classmethod` when a method needs access to shared class-level state via `cls` (e.g., updating `raise_amount` for all instances).

Briefing

Class methods and static methods solve two different problems in Python class design: class methods let code operate on shared class-level state (and can act like alternative constructors), while static methods bundle related utility logic without needing an instance or the class.

A regular instance method automatically receives the instance as its first argument (conventionally named `self`). To switch that behavior so the method receives the class instead, the tutorial adds the `@classmethod` decorator. The new method, `set_raise_amount`, takes `cls` as the first parameter and an `amount` as the second. Inside the method, it updates a class variable—`cls.raise_amount`—so the change applies across all instances. The example starts with `raise_amount` set to 4%, prints the class value and the values on two `Employee` instances, then calls `employee.set_raise_amount(5%)`. After the call, both instances reflect the new 5% because they reference the same shared class variable. Even calling the class method from an instance still updates the class variable, though that calling style is discouraged because it obscures what’s actually being modified.

The tutorial then connects class methods to a common design pattern: alternative constructors. Instead of forcing users to manually parse inputs before creating objects, a class method can accept a different input format and return a fully constructed instance. Using a realistic scenario, it shows employees represented as hyphen-separated strings containing first name, last name, and salary. Without help, a user would have to split the string, extract fields, and pass them into the normal constructor (which triggers `__init__`). The `from_string` class method removes that burden: it accepts `employee_string`, splits it on `-`, creates a new `Employee` by calling the constructor with the parsed values, and returns the new object. The result is the same as manual parsing, but the class provides a cleaner, safer entry point.

For a real-world parallel, the tutorial points to Python’s `datetime` module, where multiple constructors exist. The default constructor takes year, month, and day, while class methods like `fromtimestamp` accept a timestamp and build the corresponding `datetime` object by parsing and returning a new instance.

Static methods address a different need. They don’t receive `self` or `cls` automatically, so they behave like plain functions placed inside a class for organizational clarity. The tutorial defines `is_workday` as a `@staticmethod` that takes a `day` argument and returns whether it falls on a weekday. It uses Python’s `weekday()` convention (Monday = 0 through Sunday = 6) to return `False` for 5 (Saturday) and 6 (Sunday), and `True` otherwise. A practical rule of thumb is offered: if a method doesn’t access instance state (`self`) or class state (`cls`), it likely belongs as a static method.

By the end, the distinctions are clear: class methods operate on the class and can create objects from alternate inputs; static methods provide class-related utilities without depending on either instance or class state.

Cornell Notes

Python’s method types differ by what gets passed in automatically. Regular instance methods receive `self` (the instance) first. Class methods use `@classmethod` and receive `cls` (the class) first, making them ideal for updating class variables like `raise_amount` across all instances and for alternative constructors such as `from_string`, which parses a hyphen-separated string and returns a new `Employee`. Static methods use `@staticmethod` and receive neither `self` nor `cls`, so they act like regular functions grouped inside a class—useful for logic like `is_workday` that depends only on explicit arguments. These choices clarify when shared state or object creation logic belongs on the class versus when utility logic should stand alone.

How does a class method change the first argument a method receives compared with a regular instance method?

A regular instance method automatically receives the instance as the first argument (conventionally `self`). Adding the `@classmethod` decorator changes that behavior so the method automatically receives the class as the first argument (conventionally `cls`). In the example, `set_raise_amount(cls, amount)` updates `cls.raise_amount`, not an instance attribute.

Why do two different `Employee` instances both reflect the updated `raise_amount` after calling `employee.set_raise_amount(5%)`?

Because `raise_amount` is a class variable shared by all instances. The class method assigns `cls.raise_amount = amount`, so the single class-level value changes. Both instances read that same shared value, so printing `Employee.raise_amount` and each instance’s `raise_amount` shows the updated percentage.

What makes a class method an “alternative constructor,” and how does `from_string` demonstrate it?

An alternative constructor provides another way to create objects from different input formats. `from_string` accepts a single `employee_string`, splits it on `-` into first name, last name, and pay, then constructs a new `Employee` using those parsed values and returns the new object. This avoids forcing callers to parse the string themselves.

What is the key behavioral difference between class methods and static methods in terms of automatic arguments?

Class methods automatically receive `cls` (the class) as the first argument, while static methods receive neither `self` nor `cls` automatically. Static methods therefore don’t depend on instance or class state and instead operate purely on the arguments explicitly passed in.

How does the `is_workday` static method decide whether a given date is a workday?

It calls `day.weekday()` where Monday is 0 and Sunday is 6. It returns `False` when the weekday value is 5 (Saturday) or 6 (Sunday), and returns `True` otherwise (Monday through Friday). The method doesn’t reference `self` or `cls`, so it fits naturally as a static method.

Review Questions

  1. When should a method be implemented as a class method instead of a regular instance method? Give an example based on shared class variables.
  2. Why does calling a class method from an instance still update the class variable, and why is that calling style discouraged?
  3. What input-parsing problem does `from_string` solve, and what does it return?

Key Points

  1. 1

    Use `@classmethod` when a method needs access to shared class-level state via `cls` (e.g., updating `raise_amount` for all instances).

  2. 2

    Class methods can be called from instances, but the clearer intent is to call them on the class to signal that class state is being modified.

  3. 3

    Treat class methods as alternative constructors when callers need to create objects from different input formats (like a hyphen-separated string).

  4. 4

    Use `@staticmethod` for logic that belongs with a class conceptually but doesn’t require `self` or `cls`; it should operate only on explicit arguments.

  5. 5

    A practical rule: if a method never reads instance variables (`self`) or class variables (`cls`), it likely should be static.

  6. 6

    When designing constructors, returning a newly created object from an alternative constructor keeps object creation consistent and encapsulated.

Highlights

Updating `cls.raise_amount` inside `set_raise_amount` changes the value for every existing instance because instances share the same class variable.
`from_string` turns a messy “parse-then-construct” workflow into a single call that parses the input and returns a ready-to-use object.
Static methods like `is_workday` don’t receive `self` or `cls`; they’re effectively regular functions organized under a class.
The `datetime` module mirrors this pattern with constructors such as `fromtimestamp`, which build objects from different input types.

Topics

  • Class Methods
  • Static Methods
  • Alternative Constructors
  • Class Variables
  • Instance Methods

Mentioned