Hello! Welcome to the third lesson in our module on Object-Oriented Programming in Python.
In our last lesson, we explored inheritance and saw how a child class can inherit and override methods from a parent class. We focused on methods that are tied to a specific object or instance, which always take self as their first argument.
Today, we're going to expand our toolkit. This lesson addresses the learning outcome: Use class methods, static methods, and properties. We'll cover:
- Class Methods: Methods that operate on the class itself, not the instance.
- Static Methods: Functions that are grouped within a class for logical reasons but don't depend on the instance or the class.
- Properties: A Pythonic way to manage attribute access, allowing you to create "getters" and "setters" without changing your class's public interface.
Understanding these concepts is key to designing flexible and robust classes, a skill that's invaluable when working with complex machine learning frameworks.
Regular Instance Methods: A Quick Recap
So far, every method we've written has been an instance method.
class Employee:
def __init__(self, first, last):
self.first = first
self.last = last
# This is an instance method
def fullname(self):
return f'{self.first} {self.last}'
The fullname method needs a specific instance (via self) to do its job. You can't call Employee.fullname() because it wouldn't know which employee's name to return.
But what if a method's logic is related to the class as a whole?
Class Methods: Working with the Class
A class method is bound to the class, not the object. Instead of the instance (self), it implicitly receives the class itself as the first argument, conventionally named cls.
You create one using the @classmethod decorator.

Class methods have two primary use cases:
- Modifying class-level state.
- Serving as alternative constructors (factory methods).
Let's see this in action. The following video continues with the Employee class example from our previous lessons.
Python OOP Tutorial 3: classmethods and staticmethods
This segment from Corey Schafer's tutorial explains what class methods are, how to create them with the @classmethod decorator, and demonstrates their two main use cases.
Watch from 00:20 to 10:21. Pay close attention to: How @classmethod changes the first argument from self to cls. How a class method can be used to modify a class variable (like raise_amount). The concept of using class methods as 'alternative constructors', like creating an employee from a string.
As the video showed, using a class method as an alternative constructor is an extremely powerful pattern. Imagine you need to create objects from various data sources like a string, a dictionary from a JSON file, or a row from a database. Instead of cluttering your __init__ with complex logic, you can provide clean, separate class methods for each case.
class Employee:
# ... __init__ and other methods ...
@classmethod
def from_string(cls, emp_str):
# Parses a string like "John-Doe-70000"
first, last, pay = emp_str.split('-')
# 'cls' here refers to the Employee class
return cls(first, last, int(pay))
# Now we can create an instance directly from a string
new_emp = Employee.from_string('Jane-Doe-90000')
print(new_emp.email) # Output: Jane.Doe@company.com
Static Methods: Logically Grouped Functions
What if a method doesn't need access to the instance (self) or the class (cls)? That's when you use a static method.
A static method is essentially a regular function that lives inside a class's namespace, usually because it's logically related to the class. You create one using the @staticmethod decorator.
Let's continue with the video to see a practical example.
Python OOP Tutorial 3: classmethods and staticmethods
This final part of the video explains static methods, showing how they behave like regular functions but are organized within the class.
Watch from 10:21 to 14:29. Focus on why the is_workday function makes sense as a static method: it's related to employees, but it doesn't need any specific employee's data or class data to work.
A good rule of thumb for deciding between method types is:
- Does it need the instance's data (
self)? Use an instance method. (Most common) - Does it need the class's data (
cls), like for an alternative constructor? Use a class method. - Does it need neither? Use a static method for organizational purposes.

Test your understanding!
You are building a Car class. For each of the following functions, decide whether it should be an instance method, a class method, or a static method.
- A function
description()that returns a string like "A 2023 Toyota Camry". - A function
from_database_record()that takes a dictionary (e.g.,{'make': 'Ford', 'model': 'Mustang', 'year': 2022}) and creates aCarobject. - A function
is_valid_vin()that takes a Vehicle Identification Number (string) and checks if it follows a standard format (e.g., is 17 characters long).
Show answer
- Instance method. It needs access to the specific car's
year,make, andmodelattributes (i.e.,self). - Class method. It's an alternative way to construct a
Carobject. It needs access to the class (cls) to callcls(make, model, year). - Static method. It performs a validation check that is logically related to cars, but it doesn't need information about a specific car instance or the
Carclass itself. It just operates on the input it's given.
Properties: Accessing Methods Like Attributes
Let's revisit our Employee class. We have a problem with dependent attributes.
emp_1 = Employee('John', 'Smith', 50000)
print(emp_1.first) # John
print(emp_1.email) # John.Smith@company.com
# Let's change the first name
emp_1.first = 'Jim'
print(emp_1.first) # Jim
print(emp_1.email) # John.Smith@company.com <- PROBLEM! The email did not update.
The email was created once in __init__ and is now out of sync. We could turn email into a method (emp_1.email()), but that would force anyone using our class to change their code from emp_1.email to emp_1.email(). This is not ideal.
The @property decorator provides a solution. It lets us "wrap" a method so that it can be accessed like an attribute. This is often called a "getter".
Python OOP Tutorial 6: Property Decorators - Getters, Setters, and Deleters
This excellent video from Corey Schafer introduces the @property decorator to solve the exact problem we just described. It shows how to create getters, setters, and deleters.
Watch from the beginning to 08:08. Pay attention to: How @property allows you to access a method as an attribute (the 'getter'). The syntax for creating a 'setter' (@property_name.setter) to allow modification. The syntax for the 'deleter' (@property_name.deleter).
Let's summarize the three parts of a property:
-
Getter (
@property): Makes a method accessible as an attribute. It computes and returns a value on the fly.@property def email(self): return f'{self.first}.{self.last}@email.com' # Now emp_1.email always returns the up-to-date email -
Setter (
@<property_name>.setter): Allows you to assign a value to the property, running custom code in the process.@fullname.setter def fullname(self, name): first, last = name.split(' ') self.first = first self.last = last # emp_1.fullname = 'Corey Schafer' now works and updates self.first and self.last -
Deleter (
@<property_name>.deleter): Defines custom behavior for when the attribute is deleted withdel.@fullname.deleter def fullname(self): print('Deleting name!') self.first = None self.last = None
For a deeper dive and more examples of when to use each of these decorators, the following article is an excellent resource.
Keys to Mastering Python Method Decorators
The article 'Keys to Mastering Python Method Decorators' by Heval Hazal Kurt provides a thorough explanation with clear use cases for @classmethod, @staticmethod, and @property.
Skim through the sections on @classmethod, @staticmethod, and @property. Focus on the 'When to Use' and 'Use Cases' subsections for each to solidify your understanding of their practical applications. Don't worry about the more advanced metaprogramming examples for now.
Conclusion
In this lesson, you've significantly upgraded your OOP toolkit. You now have fine-grained control over how methods and attributes behave in your classes.
Key Takeaways:
- Instance Methods operate on an object's state (
self). @classmethodmethods operate on the class itself (cls) and are ideal for alternative constructors or modifying class-level variables.@staticmethodmethods are utility functions that don't depend on instance or class state but belong logically within the class.@propertyallows you to create getters, setters, and deleters, enabling computed attributes and controlled access while maintaining a clean, attribute-like interface.
Preview of the Next Lesson:
Properties are a Pythonic way to manage access to an object's internal data. This is a core part of a broader OOP principle called encapsulation. In our next lesson, "Apply encapsulation principles using private and protected attributes," we will explore how Python signals that certain attributes are for internal use and should not be modified directly from outside the class.