Recommended Video Course
OOP Method Types in Python: @classmethod vs @staticmethod vs Instance Methods
Table of Contents
Watch Now This tutorial has a related video course created by the Real Python team. Watch it together with the written tutorial to deepen your understanding:OOP Method Types in Python: @classmethod vs @staticmethod vs Instance Methods
Instance, class, and static methods each serve a distinct role in Python, and knowing when to use one over another is key to writing clean, maintainable code. Instance methods operate on individual objects usingself
, while class methods usecls
to access class-level data. Static methods, on the other hand, provide organizational structure without relying on class or instance state.
When you understand the differences between these three method types, you’ll be in a better spot to know when to write an instance method, class method, or a static method. Ultimately, this’ll help you design better maintainable object-oriented Python code.
By the end of this tutorial, you’ll understand that:
self
parameter.@classmethod
decorator and use them for operations that involveclass-level data.@staticmethod
decorator.Keep reading to see all three method types in action. You’ll even bake some digital pizza while working on a real-world example with all three method types in aPizza
class.If you develop an intuitive understanding for their differences, you’ll be able to writeobject-oriented Python code that communicates its intent more clearly and is easier to maintain in the long run.
Get Your Code:Click here to download the free sample code you’ll use to learn about instance, class, and static methods in Python.
Take the Quiz: Test your knowledge with our interactive “Python's Instance, Class, and Static Methods Demystified” quiz. You’ll receive a score upon completion to help you track your learning progress:
Interactive Quiz
Python's Instance, Class, and Static Methods DemystifiedIn this quiz, you'll test your understanding of instance, class, and static methods in Python. By working through this quiz, you'll revisit the differences between these methods and how to use them effectively in your Python code.
If you’re here for a quick reminder of how the three method types differ from one another, then consider the following overview that compares them:
Instance methods use aself
parameter pointing to aninstance of theclass. They can access and modify instance state throughself
and class state throughself.__class__
. These are the most common methods in Python classes.
Class methods use acls
parameter pointing to the class itself. They can modify class-level state throughcls
, but they can’t modify individual instance state.
Static methods don’t takeself
orcls
parameters. They can’t modify instance or class state directly, and you’ll mainly use them for organizational purposes and namespacing.
If you need to revisit information quickly, there’s nothing quite like a table. So here are the most important aspects of the three different types of methods in Python classes summed up in a table:
Type | Decorator | Parameter | Instance Access | Class Access | Use Case |
---|---|---|---|---|---|
Instance | None needed | self | ✅ | ✅ | Operations on individual instances. |
Class | @classmethod | cls | ❌ | ✅ | Factory methods, alternative constructors, or any method that deals with class-level data. |
Static | @staticmethod | Noself orcls | ❌ | ❌ | Utility methods that don’t need instance or class data. |
That’s enough super-condensed, repetitive reference information! If you want to know what all of this means in practice, and you like to learn by running code snippets and reasoning about them, then keep on reading.
Next, you’ll explore the differences between instance, class, and static methods in a somewhat abstract code example. Abstract you say? Don’t worry—it involves runnable code, and it’s there to set the stage for a more practical example later on.
To get warmed up, you’ll write a small Python file calleddemo.py
with a bare-bones Python class that contains stripped-down examples of all three method types:
demo.py
classDemoClass:definstance_method(self):return("instance method called",self)@classmethoddefclass_method(cls):return("class method called",cls)@staticmethoddefstatic_method()return("static method called",)
Insidedemo.py
, you createDemoClass
—a descriptively named custom class with the sole purpose of demoing the differences between instance methods, class methods, and static methods.
Consequently, you also implement one of each of the three method types and name them accordingly. They each return atuple containing information to help you trace what’s going on, as well as the arguments the method received, such asself
andcls
. The output will help you understand whichobjects each of the methods can access.
Note: Naming these parametersself
andcls
is just a convention—but it’s a strong one in the Python community! You could name themfoo
andbar
and get the same result. However, if you stray from the convention, then you may get disapproving looks from your coworkers or anyone reading your code.
For functionality, all that matters is that you position them first in the parameter list for the method. For maintainability, sanity, and out of respect for others, you should always useself
andcls
in the classes you define.
Now it’s time to call these demo methods in a newREPL session. ImportDemoClass
and create an instance of it, then start by calling theinstance method:
>>>fromdemoimportDemoClass>>>obj=DemoClass()>>>obj.instance_method()('instance method called', <demo.DemoClass object at 0x100a30d70>)
The output confirms that.instance_method()
has access to the object instance through theself
argument. Python prints the object instance as<demo.DemoClass object at 0x100a30d70>
. When you call the instance method, Python replaces theself
argument with the instance object,obj
.
Instance methods can also access the class itself through theself.__class__
attribute. This makes instance methods powerful in terms of access restrictions. They can modify state on the object instanceand on the class itself.
Next, you can try out theclass method:
>>>obj.class_method()('class method called', <class 'demo.DemoClass'>)
Calling.class_method()
shows that the method doesn’t have access to theDemoClass
instance object that the instance method had access to. However, it can access the class, which you can see by the output<class 'demo.DemoClass'>
. This output represents the class object itself. Remember that everything in Python is an object, even classes themselves!
Notice how Python automatically passes the class as the first argument to the function when you callobj.class_method()
. Calling a class method in Python through thedot notation triggers this behavior. Theself
parameter on instance methods works in the same way. Now, Python automatically passes the instance as the first argument when you call an instance method on an instance object.
Finally, it’s time to call thestatic method:
>>>obj.static_method()('static method called',)
You get your information message as output but no additional objects. This confirms that static methods can neither access the object instance state nor the class state. They work like regular functions but belong to the namespace of the class. They also belong to the namespace of each instance.
Note: Were you surprised that you can successfully call.static_method()
directly on the instance object? Behind the scenes, Python enforces access restrictions by not passing inself
orcls
when you call a static method using the dot notation.
Now, take a look at what happens when you attempt to call these methods on the class itself without creating an object instance beforehand. To do this properly, you should start a newREPL session to ensure there are no existing instances of the class:
>>>fromdemoimportDemoClass>>>DemoClass.class_method()('class method called', <class 'demo.DemoClass'>)>>>DemoClass.static_method()('static method called',)>>>DemoClass.instance_method()Traceback (most recent call last):...TypeError:DemoClass.instance_method()⮑ missing 1 required positional argument: 'self'
You’re able to call.class_method()
and.static_method()
just fine, but attempting to call.instance_method()
fails with aTypeError
.
This is to be expected because in this case, you didn’t create an object instance and tried calling an instance method directly on the class itself. Since there’s no way for Python to populate theself
argument, the call fails.
However, you don’tneed to call an instance method on the instance object like you did previously. In the end, that’s justsyntactic sugar that Python implements to make the call more intuitive. If you want, you can ignore the syntactic sugar of the dot notation syntax and pass the instance object manually to get the same result:
>>>obj=DemoClass()>>>DemoClass.instance_method(obj)('instance method called', <demo.DemoClass object at 0x100a30d70>)
In this case, you manually pass theobj
instance to the instance method while calling the instance method on the class object. Doing so produces the same result as calling the instance method on the instance, without explicitly passingself
.
Now that you’ve worked through this bare-bones example and have a better understanding of how the different method types work, you’re ready to look at a more realistic example of when to use each of the three method types.
The basic example from the previous section shows the distinction between instance methods, class methods, and static methods. However, it’s quite abstract and doesn’t give you a good idea of why and when you might want to use one method type over another. To connect what you learned with the real world, you’ll now explore this topic with a more realistic example.
Everyone loves pizza, so it’ll be your delicious and circular gateway to implementing instance methods, class methods, and a static method in the real world. Go ahead and define a basicPizza
class inpizza.py
:
pizza.py
classPizza:def__init__(self,toppings):self.toppings=list(toppings)def__repr__(self):returnf"Pizza({self.toppings})"
The class contains the twospecial methods.__init__()
and.__repr__()
. Both of these methods operate on the instance, so you don’t need to add adecorator. It’s common to set up these two special methods for most of your custom Python classes:
.__init__()
controls object instantiation..__repr__()
provides a string representation for when you need to display an object.If you’re not familiar with these two special methods, then you may want to first read more aboutclass constructors andcustomizing object rerpresentation. But feel free to skip that and keep going with this tutorial.Understanding special methods isn’t crucial to grasp how to distinguish between instance, class, and static methods.
ThePizza
class defines a dataattribute called.toppings
. You can use anyiterable containing the pizza toppings when you create an instance of the class. However, the.__init__()
method casts this into alist, as your class definition will assume this attribute is a list.
You can explore your newPizza
class in a REPL session:
>>>frompizzaimportPizza>>>Pizza(["cheese","tomatoes"])Pizza(['cheese', 'tomatoes'])
Yum! Cheese and tomato pizza. That’s already a good start, but of course there’s a lot more to pizza. You want to customize the toppings on your pizza, so it’s time to add two instance methods that can handle the task.
Instance methods are the most common methods in Python classes. You use them when you want to implement functionality that can access and change the state of an instance.
Maybe you’ll have to deal with fussy customers in a pizza restaurant who want to change the toppings on their pizza. So, you’ll go ahead and add two instance methods to yourPizza
class.
As you learned earlier, an instance method is a function that has access to a specific instance of the class. Therefore, an instance method can change the data stored in the object.
The Python community uses the parameter nameself
by convention to refer to the instance within an instance method. It’s so common that yourintegrated development environment (IDE) may automatically fill this parameter for you.
Add two instance methods called.add_topping()
and.remove_topping()
to the class:
pizza.py
classPizza:# ...defadd_topping(self,topping):self.toppings.append(topping)defremove_topping(self,topping):iftoppinginself.toppings:self.toppings.remove(topping)
With this edit topizza.py
, you add two new instance methods that can change the state of aPizza
instance—allowing you to add and remove toppings to satisfy your customers’ every taste bud. You can now call these instance methods in a new REPL session to try out their functionality:
>>>frompizzaimportPizza>>>a_pizza=Pizza(["cheese","tomatoes"])>>>a_pizzaPizza(['cheese', 'tomatoes'])>>>a_pizza.add_topping("garlic")>>>a_pizzaPizza(['cheese', 'tomatoes', 'garlic'])>>>a_pizza.remove_topping("cheese")>>>a_pizzaPizza(['tomatoes', 'garlic'])
The data contained within the attribute.toppings
changes when you call these instance methods. Therefore, aPizza
instance contains the data about the toppings and the ability to make changes to the data. This is the key principle of objects inobject-oriented programming.
So, when should you use instance methods? In short, you should use instance methods when you need to access and edit the data that an instance of your class holds.
You use a class method when you need to access or modify class-level data, such as class attributes. Another common use case for@classmethod
is to create factory methods that return class instances with specific configurations.
Everyone has their favorite pizza variation, and with the existing code you can already create an endless number of delicious pizza variations:
>>>Pizza(["mozzarella","tomatoes"])Pizza(['mozzarella', 'tomatoes'])>>>Pizza(["mozzarella","tomatoes","ham","mushrooms"])Pizza(['mozzarella', 'tomatoes', 'ham', 'mushrooms'])>>>Pizza(["mozzarella"]*4)Pizza(['mozzarella', 'mozzarella', 'mozzarella', 'mozzarella'])
However, the Italians figured out their pizza taxonomy centuries ago, so each delicious type of pizza has its own name. It’s a good idea to take advantage of that rich pizza history and give the users of yourPizza
class a better interface for creating the types of pizza they crave.
A nice, clean way to do that is by using class methods asfactory methods for the different kinds of pizza you can create:
pizza.py
classPizza:# ...@classmethoddefmargherita(cls):returncls(["mozzarella","tomatoes"])@classmethoddefprosciutto(cls):returncls(["mozzarella","tomatoes","ham"])
Note how the.margherita()
and.prosciutto()
factory methods use thecls
argument instead of calling thePizza
constructor directly.
This is a trick you can use to follow theDon’t Repeat Yourself (DRY) principle. If you decide to rename this class at some point, you won’t have to remember to update the constructor name in all of the factory methods.
Now, what can you do with these factory methods? It’s time to try them out. Since you made changes topizza.py
, you’ll need a new REPL session:
>>>frompizzaimportPizza>>>Pizza.margherita()Pizza(['mozzarella', 'tomatoes'])>>>Pizza.prosciutto()Pizza(['mozzarella', 'tomatoes', 'ham'])
You can use the factory methods to create newPizza
objects that are configured the way you want them. They all use the same.__init__()
constructor internally and simply provide a shortcut for remembering the various toppings.
Since these methods still create an instance of the class, you can also use other methods on the instances they create, such as.add_topping()
:
>>>a_pizza=Pizza.prosciutto()>>>a_pizzaPizza(['mozzarella', 'tomatoes', 'ham'])>>>a_pizza.add_topping("garlic")>>>a_pizzaPizza(['mozzarella', 'tomatoes', 'ham', 'garlic'])
Another way to look at this use of class methods is that they allow you to definealternative constructors for your classes.
Python only allows one.__init__()
method per class, but it’s possible to add as many alternative constructors as necessary by using class methods. This can make the interface for your classes self-documenting and simplify their usage.
So, when should you use class methods? In short, you should use class methods when you need to access and edit the data that’s tied to your class object rather than an instance of it. You can also use them to create alternative constructors for your class.
You can use static methods when you need utility functions that don’t access or modify class or instance data, but where the functionality they provide still logically belongs within the class’s namespace.
Let’s stretch the pizza analogy even thinner, and add a static method that allows users to quickly fetch the diameter in inches based on common pizza sizes:
pizza.py
classPizza:# ...@staticmethoddefget_size_in_inches(size):"""Returns the diameter in inches for common pizza sizes."""size_map={"small":8,"medium":12,"large":16,}returnsize_map.get(size,"Unknown size")
You added a static method.get_size_in_inches()
that allows you to input a string describing a pizza size. The method then returns the diameter of that size in inches.
The static method doesn’t have access to the instance or the class—and it doesn’t need that access. All that the method does is perform adictionary lookup to return a number. You can call the static method both on aPizza
instance and the class itself:
>>>frompizzaimportPizza>>>a_pizza=Pizza(["mozzarella","tomatoes"])>>>a_pizza.get_size_in_inches("medium")12>>>Pizza.get_size_in_inches("small")8
That functionality makes sense because the toppings on a pizza won’t influence what size your medium pizza will be—even though you may wish that it did!
It’s purely for convenience and organizational purposes that static methods are part of the namespaces of the class and the instance. That convenience can be helpful because as a programmer-turned-pizza-baker, you may still sometimes need to look up how large a specific size of pizza should be. With.get_size_in_inches()
, you can do that quickly.
Static methods can’t access class or instance state because they don’t take acls
orself
argument. While this may seem like a limitation, it also clearly signals that the method is independent of everything else in the class.
Flagging a method as a static method is a hint that a method won’t modify class or instance state. This restriction is also enforced by the Python runtime. Using@staticmethod
enables you to communicate clearly about parts of your class architecture so that new development work is naturally guided to happen within these set boundaries.
Note: Of course, it’s possible to defy these restrictions. But in practice, static methods can often help prevent accidental modifications that would go against the original design intent.
Static methods also have benefits when it comes towriting test code since they’re completely independent from the rest of the class. You don’t have to worry about setting up a complete class instance before you can test the static method in aunit test. You can just fire away like you would to test a regular function. This can make future maintenance less of an effort.
So, when should you use static methods? In short, you should use static methods when you want to tie utility functionality related to your class right into its namespace.
By now, you’ve seen that instance, class, and static methods each play a distinct role in designing maintainable, object-oriented Python code. When you use them intentionally, these three method types can improve your code’s clarity, reusability, and testability.
In this tutorial, you learned that:
self
.cls
.The next time you design a Python class, take a moment to consider whether your methods need access to instance data, class data, or neither. If it makes sense, then place a decorator before your method definition to make your code both more readable and more robust.
Use all three method types in combination with Python’s other object-oriented features to create classes that are intuitive to read and straightforward to maintain. Happy coding—and happy pizza-making!
Get Your Code:Click here to download the free sample code you’ll use to learn about instance, class, and static methods in Python.
Now that you have some experience with instance, class, and static methods in Python, you can use the questions and answers below to check your understanding and recap what you’ve learned.
These FAQs are related to the most important concepts you’ve covered in this tutorial. Click theShow/Hide toggle beside each question to reveal the answer.
An instance method requires a class instance and accesses it throughself
, allowing you to modify instance-specific data. A class method usescls
to access and modify class-level data without needing an instance.
Use an instance method when you need to perform operations that modify or rely on the instance’s specific data and state.
Use a class method when you need to access or modify class-level data or create factory methods that return class instances with specific configurations.
Use a static method when you need a utility function that doesn’t access or modify class or instance data, but logically belongs within the class’s namespace.
Class methods and static methods help communicate developer intent, provide structure, and enforce boundaries in class design, making code easier to maintain and understand.
Take the Quiz: Test your knowledge with our interactive “Python's Instance, Class, and Static Methods Demystified” quiz. You’ll receive a score upon completion to help you track your learning progress:
Interactive Quiz
Python's Instance, Class, and Static Methods DemystifiedIn this quiz, you'll test your understanding of instance, class, and static methods in Python. By working through this quiz, you'll revisit the differences between these methods and how to use them effectively in your Python code.
Watch Now This tutorial has a related video course created by the Real Python team. Watch it together with the written tutorial to deepen your understanding:OOP Method Types in Python: @classmethod vs @staticmethod vs Instance Methods
🐍 Python Tricks 💌
Get a short & sweetPython Trick delivered to your inbox every couple of days. No spam ever. Unsubscribe any time. Curated by the Real Python team.
AboutMartin Breuss
Martin is Real Python's Head of Content Strategy. With a background in education, he's worked as a coding mentor, code reviewer, curriculum developer, bootcamp instructor, and instructional designer.
» More about MartinMasterReal-World Python Skills With Unlimited Access to Real Python
Join us and get access to thousands of tutorials, hands-on video courses, and a community of expert Pythonistas:
MasterReal-World Python Skills
With Unlimited Access to Real Python
Join us and get access to thousands of tutorials, hands-on video courses, and a community of expert Pythonistas:
What Do You Think?
What’s your #1 takeaway or favorite thing you learned? How are you going to put your newfound skills to use? Leave a comment below and let us know.
Commenting Tips: The most useful comments are those written with the goal of learning from or helping out other students.Get tips for asking good questions andget answers to common questions in our support portal.
Keep Learning
Related Topics:intermediatepython
Recommended Video Course:OOP Method Types in Python: @classmethod vs @staticmethod vs Instance Methods
Related Tutorials:
Already have an account?Sign-In
Almost there! Complete this form and click the button below to gain instant access:
Python's Instance, Class, and Static Methods Demystified (Sample Code)