Python OOP for Beginners — Class Method & Static Method


Most programmers stick only to instance methods, while there are two other types of methods — class methods and static methods — that can greatly improve your code quality. If the reason you don’t use them is simply a lack of understanding of when and why to use them, this guide is a must-read.
Introduction
As mentioned earlier, Python classes have three types of methods:
Instance Methods
Class Methods
Static Methods In the previous article, we covered instance methods. In this one, you’ll gain a clear understanding of class methods and static methods.
Now, to be honest, you can write entire software without ever using a single class method or static method. But if you truly care about the quality of your code — readability, maintainability, and flexibility — then understanding these two concepts is essential.
Static Method
The concept of static method is actually easier to understand than the concept of instance method. It's just a function inside a class. Unlike instance methods, you don’t add a self
parameter because static methods don’t depend on any instance.
That means you don’t need to create an object to call them — they can be called directly on the class.
The syntax might look a bit intimidating at first since it involves decorators, but don’t worry — you don’t need to fully understand decorators to use static methods and class methods.
Dog Years to Human Years
Here's our current Dog
class.
class Dog:
def __init__(self,name,breed,color,age):
self.name = name
self.breed = breed
self.color = color
self.age = age
def run(self):
print(self.name, 'is running.')
def sleep(self):
print(self.name,'is sleeping.')
def eat(self):
print(self.name, 'is eating.')
Dogs don't live as long as humans. So let's create a function to covert dog years into human years using the following formula.
$$Human\;Years = Dog\;Years \times 7$$
Let's first create it as an instance method.
def dog_years_2_human_years(self):
return self.age*7
Usage:
tommy = Dog('Tommy','Labrador Retriever','Black',2)
print(tommy.dog_years2human_years())
It works fine. But what if you just want to convert any dog’s age into human years — not just the age of a Dog
object you’ve created?
This won't work:
human_years = Dog.dog_years_2_human_years(4)
Why?
dog_years_2_human_years
is an instance method. You must create an instance before call it.It doesn't accept
dog_years
as a parameter — it expectsself
(an instance).
So here, you’re basically trying to pass an integer to self
, which makes no sense.
In a scenario, you need to define a method inside a function but you need it to be able to use it not only inside the class but also outside the class without creating an instance, you can use static methods.
Static methods still belong to the class. The only difference is that they don’t need an instance (
self
) or the class (cls
) to work. They’re just independent functions that are namespaced inside the class.
Let's modify dog_years_2_human_years
as a static method.
@staticmethod
def dog_years_2_human_years(dog_years):
return dog_years*7
What has have changed here?
We have used the
@staticmethod
decorator to mark thedog_years_2_human_years
as a static method.We have replaced
self
with a parameterdog_years
because static methods don’t depend on instances.We replaced
self.age
withdog_years
.
Now we can call it in different ways:
# Without creating an instance
human_years = Dog.dog_years_2_human_years(3)
print(human_years)
# With creating an instance
tommy = Dog('Tommy','Labrador Retriever','Black',2)
human_years = tommy.dog_years_2_human_years(2)
print(human_years)
And even use it inside the class.
def age_in_human_years(self):
return self.dog_years_2_human_years(self.age)
dora = Dog('Dora','German Shepherd','Black & Tan',6)
print(dora.age_in_human_years())
Class Method
Class methods are mostly used for:
Factory methods (alternative ways to create objects)
Accessing or modifying class-level data
Let’s start with factory methods.
Factory Methods
Here's how we normally create a instance.
dora = Dog('Dora','German Shepherd','Black & Tan',6)
But what if we want to create an instance from a string or a list like below?
dora_data_str = 'Dora,German Shepherd,Black & Tan,6'
dora_data_list = ['Dora','German Shepherd','Black & Tan',6]
With class methods, we can do this:
dog_1 = Dog.from_str(dora_data_str)
dog_2 = Dog.from_list(dora_data_list)
These are called factory methods.
Creating Factory Methods
We use the @classmethod
decorator and define cls
as the first parameter.
@classmethod
def from_str(cls,the_str):
name, breed, color, age = the_str.split(',')
return cls(name,breed,color,int(age))
cls
refers to the class itself, just likeself
refers to the instance.
In the above method, we get a string and split it to a list by ,
and assign each one of them to variables.
Puppy Factory
Suppose we want to create puppies. Since every puppy’s age is always 0
, we shouldn’t have to write that every time.
@classmethod
def puppy(cls,name,breed,color):
return cls(name,breed,color,0)
Usage:
rex = Dog.puppy('Rex','German Shepherd','Black & Tan')
Class Level Data
Class-level data (also called class attributes) belong to the class itself, not to any single object. All instances share them.
class Dog:
species = "Canis familiaris" # <-- class-level data
def __init__(self,name,breed,color,age):
self.name = name # All of these
self.breed = breed # are
self.color = color # <-- instance-level data
self.age = age #
We can access them just like instance attributes:
def print_species(self):
print(f'Species: {self.species}')
print(Dog.species)
dora = Dog('Dora','German Shepherd','Black & Tan',6)
print(dora.species)
dora.print_species()
Dog.print_species()
Class-wide operations
Here’s a great example of class-level data: tracking how many dogs we create.
class Dog:
dog_count = 0
def __init__(self,name,breed,age):
self.name = name
self.breed = breed
self.age = age
Dog.dog_count += 1 # class wide operation
tommy = Dog('tommy','Labrador Retriever',3)
print(Dog.dog_count)
dora = Dog('dora','German Shepherd',6)
print(Dog.dog_count)
luca = Dog('luca','Doberman',4)
print(Dog.dog_count)
Each time we create a new dog, dog_count
increases because it belongs to the class, not to any single object.
Class Methods for Class Data
Let's reset our class to following one.
class Dog:
species = ""
def __init__(self,name,breed,age):
self.name = name
self.breed = breed
self.age = age
Yet, the species
class data is an empty string. So, Let’s add a class method to modify the species
:
@classmethod
def set_species(cls,species):
cls.species = species
Usage:
print(Dog.species)
Dog.set_species('Canis familiaris')
print(Dog.species)
Final Thoughts
By now, you should feel confident about when to use instance methods, class methods, and static methods. These techniques improve flexibility, readability, and maintainability of your code.
In the upcoming article, we’ll move to another key concept of OOP: encapsulation. You’ll learn how Python lets you control access to attributes, enforce restrictions, and design cleaner, safer class structures.
You can subscribe to the newsletter to get new articles delivered straight to your inbox the moment I post them. Follow me on GitHub for more contents— and maybe Instagram too.
You can support my effort by reacting to and commenting on this article. Share it with someone who would find it valuable.
Subscribe to my newsletter
Read articles from Beenuka Hettiarachchi directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
