How to make a method in Python

Learn how to make a method in Python. Explore different techniques, tips, real-world applications, and how to debug common errors.

How to make a method in Python
Published on: 
Tue
Apr 21, 2026
Updated on: 
Wed
Apr 22, 2026
The Replit Team

Methods in Python are reusable blocks of code that perform specific actions within a class. They are a core concept in object-oriented design and help keep your code organized.

In this article, we'll cover techniques to define and call methods. We'll also share practical tips, real-world applications, and advice for common bugs to help you master them.

Creating a simple method in a class

class Calculator:
def add(self, a, b):
return a + b

calc = Calculator()
result = calc.add(5, 3)
print(result)--OUTPUT--8

The add function is defined as an instance method within the Calculator class. The key here is the self parameter, which is a reference to the specific instance of the class—in this example, the calc object.

  • When you call calc.add(5, 3), Python automatically passes the calc object as the first argument to the method.
  • This allows the method to access the object's attributes and other methods, distinguishing it from a standalone function.

This design is central to object-oriented programming, enabling methods to operate on the unique state of each object.

Essential method variations

Building on the simple instance method, you can also define class and static methods that interact with the class rather than individual objects.

Using instance methods with parameters

class Person:
def __init__(self, name, age):
self.name = name
self.age = age

def introduce(self, greeting="Hello"):
return f"{greeting}, I'm {self.name} and I'm {self.age} years old."

person = Person("Alice", 30)
print(person.introduce())
print(person.introduce("Hi there"))--OUTPUT--Hello, I'm Alice and I'm 30 years old.
Hi there, I'm Alice and I'm 30 years old.

The introduce method accesses the instance's unique data, like self.name and self.age, which are set when the object is created. It also shows how you can define parameters with default values, such as greeting="Hello", to make them optional.

  • When you call person.introduce() without an argument, the method falls back on the default greeting.
  • If you provide an argument, like in person.introduce("Hi there"), it overrides the default and customizes the output.

Creating class methods with @classmethod

class Employee:
company = "TechCorp"

def __init__(self, name):
self.name = name

@classmethod
def change_company(cls, new_company):
cls.company = new_company
return f"Company changed to {cls.company}"

print(Employee.company)
print(Employee.change_company("GlobalTech"))
print(Employee.company)--OUTPUT--TechCorp
Company changed to GlobalTech
GlobalTech

A class method operates on the class itself, not on an individual object. You create one by placing the @classmethod decorator above the method definition. Instead of the usual self, a class method's first parameter is conventionally named cls, which refers to the class—in this example, Employee.

  • This design is perfect for actions that involve the class as a whole, such as modifying a class attribute like company.
  • You can call the method directly on the class, as shown with Employee.change_company(), without needing to create an instance first.

Defining static methods with @staticmethod

class MathHelper:
@staticmethod
def is_prime(number):
if number <= 1:
return False
for i in range(2, int(number**0.5) + 1):
if number % i == 0:
return False
return True

print(MathHelper.is_prime(7))
print(MathHelper.is_prime(8))--OUTPUT--True
False

A static method is a utility function that lives inside a class but doesn't operate on the instance (self) or the class (cls). You create one using the @staticmethod decorator. Think of it as a regular function that's logically grouped with a class because it's relevant to its purpose.

  • The is_prime method is a perfect example—its calculation doesn't depend on any specific object or class data.
  • Because it's self-contained, you can call it directly on the class, as seen with MathHelper.is_prime(7), without needing to create an instance first.

Advanced method techniques

With the fundamentals covered, you can elevate your class designs using property methods, flexible arguments, and abstract methods to write more robust code.

Creating property methods with @property

class Circle:
def __init__(self, radius):
self._radius = radius

@property
def radius(self):
return self._radius

@property
def area(self):
return 3.14 * self._radius ** 2

circle = Circle(5)
print(f"Radius: {circle.radius}, Area: {circle.area}")--OUTPUT--Radius: 5, Area: 78.5

The @property decorator transforms a method into a read-only attribute, which is perfect for creating computed values. It makes your code cleaner because you can access the value without using parentheses, just like a regular attribute.

  • In the Circle class, area is a property that's calculated on the fly using the object's radius.
  • You access it with circle.area instead of circle.area(), making the syntax more intuitive.
  • This pattern also provides controlled access to internal attributes, like how the radius property exposes the value of _radius.

Implementing method overloading with *args and **kwargs

class MathUtils:
def calculate(self, operation, *args, **kwargs):
if operation == "sum":
return sum(args)
elif operation == "multiply":
result = 1
for num in args:
result *= num
return result

math = MathUtils()
print(math.calculate("sum", 1, 2, 3, 4))
print(math.calculate("multiply", 2, 3, 4))--OUTPUT--10
24

Python doesn't have traditional method overloading, but you can achieve similar flexibility with *args and **kwargs. These special parameters let a method accept a variable number of arguments, making your code more adaptable. The calculate method is a great example of this in action.

  • The *args parameter gathers any number of positional arguments into a tuple. This is how calculate("sum", 1, 2, 3, 4) works—it packs the numbers into a tuple for the sum() function.
  • Meanwhile, **kwargs collects keyword arguments into a dictionary, which is useful for optional named parameters.

Defining abstract methods with the abc module

from abc import ABC, abstractmethod

class Shape(ABC):
@abstractmethod
def area(self):
pass

class Rectangle(Shape):
def __init__(self, width, height):
self.width = width
self.height = height

def area(self):
return self.width * self.height

rect = Rectangle(5, 3)
print(f"Rectangle area: {rect.area()}")--OUTPUT--Rectangle area: 15

Abstract methods create a blueprint that other classes must follow. By marking a method with @abstractmethod, you're setting a rule: any class that inherits from your abstract base class (Shape in this case) must provide its own implementation for that method.

  • This approach enforces a consistent structure. The Rectangle class is required to define its own area method to fulfill the contract set by Shape.
  • You can't create an instance of an abstract class like Shape directly; it only serves as a template for concrete classes.

Move faster with Replit

Replit is an AI-powered development platform where all Python dependencies pre-installed, so you can skip setup and start coding instantly. This lets you focus on applying what you've learned, like the method techniques in this article, without getting stuck on environment configuration.

Instead of piecing these techniques together manually, you can use Agent 4 to move from an idea to a complete application. Describe the app you want to build, and the Agent handles the coding, database connections, APIs, and deployment for you.

  • A flexible calculator that uses a single calculate method to perform different operations like sum or multiply on any number of inputs.
  • A geometry dashboard that computes the area and other properties for various shapes, like circles and rectangles, based on user-provided dimensions.
  • A simple employee directory tool that manages a list of employees and updates shared company-wide information using class methods.

Simply describe your app, and Replit will write the code, test it, and fix issues automatically, all within your browser.

Common errors and challenges

Even experienced developers run into issues, but most method-related bugs fall into a few common categories.

Forgetting the self parameter in instance methods

One of the most frequent mistakes is forgetting to include self as the first parameter in an instance method. Since Python automatically passes the object instance as the first argument, leaving it out leads to a TypeError.

  • The error message often says the method received one more argument than it expected.
  • This happens because Python tries to pass the instance to a method that wasn't defined to accept it.

Incorrect method overriding in inheritance

When a subclass overrides a method from its parent, the method signatures must be compatible. A common issue is defining a child method that doesn't accept the same arguments as the parent's version, such as with a make_sound() method.

  • For example, if a parent class has make_sound(self, volume), a subclass must also accept a volume argument.
  • If the subclass method is defined as just make_sound(self), calling it with an argument will cause a TypeError.

Missing a setter implementation for a property

The @property decorator is great for creating read-only attributes, but you'll get an AttributeError if you try to assign a new value without defining a setter. For a property named celsius, this would be the @celsius.setter.

  • To make a property writable, you must implement a corresponding setter method.
  • This design forces you to explicitly define how an attribute can be changed, preventing accidental modifications.

Forgetting the self parameter in instance methods

It's a classic mistake: you define an instance method but forget to add self as the first parameter. Because Python automatically passes the object instance when the method is called, this mismatch causes a TypeError that can be confusing at first.

The code below shows what happens when the increment() method is defined without self, leading to an error when you try to call it.

class Counter:
def __init__(self):
self.count = 0

def increment(): # Missing 'self' parameter
self.count += 1

def get_count(self):
return self.count

counter = Counter()
counter.increment() # This will raise a TypeError

When counter.increment() is called, Python passes the counter object as an argument. Since the method isn't defined to accept it, a TypeError occurs. The corrected code below shows how to resolve this.

class Counter:
def __init__(self):
self.count = 0

def increment(self): # Added 'self' parameter
self.count += 1

def get_count(self):
return self.count

counter = Counter()
counter.increment()
print(counter.get_count()) # Outputs: 1

The fix is adding self as the first parameter to the increment() method. This allows the method to correctly receive the counter object that Python passes automatically on every call. With self in place, the method can access and modify the instance's attributes, like self.count.

This error is especially common when you're first getting used to classes or refactoring standalone functions into methods, so it's a good one to watch for.

Incorrect make_sound() method overriding in inheritance

When a subclass overrides a parent method, its signature must remain compatible. A common mistake is changing the parameters, like removing an optional argument. This breaks the contract with the parent class, leading to a TypeError when the method is called.

The code below shows what happens when the Dog subclass redefines the make_sound() method but omits the times parameter from the parent Animal class. This mismatch causes an error when you try to call the method with an argument.

class Animal:
def make_sound(self, times=1):
return "Generic sound" * times

class Dog(Animal):
def make_sound(self): # Missing the 'times' parameter
return "Woof!"

dog = Dog()
print(dog.make_sound(3)) # This will raise a TypeError

The call dog.make_sound(3) fails because the Dog class's method doesn't accept arguments, breaking the parent's signature and causing a TypeError. The corrected implementation below shows how to align the method signatures properly.

class Animal:
def make_sound(self, times=1):
return "Generic sound" * times

class Dog(Animal):
def make_sound(self, times=1): # Maintained same parameter
return "Woof!" * times

dog = Dog()
print(dog.make_sound(3)) # Outputs: Woof!Woof!Woof!

The fix aligns the method signatures. By adding the times=1 parameter to the Dog class's make_sound method, it now matches the parent Animal class. This compatibility is key—it allows the subclass method to handle the same calls as the parent, preventing a TypeError when an argument is passed.

  • This is a common pitfall when working with inheritance, so always double-check that a child's method signature doesn't break the contract set by its parent.

Missing @celsius.setter implementation

The @property decorator creates a read-only attribute. You'll get an AttributeError if you try assigning a new value without defining a corresponding setter, like @celsius.setter. The code below shows what happens when you try to modify the property directly.

class Temperature:
def __init__(self, celsius):
self._celsius = celsius

@property
def celsius(self):
return self._celsius

@property
def fahrenheit(self):
return (self._celsius * 9/5) + 32

temp = Temperature(25)
temp.celsius = 30 # This will raise an AttributeError

The assignment temp.celsius = 30 raises an AttributeError because the property lacks a defined setter. This means Python doesn't know how to handle writing a new value to the underlying _celsius attribute. The corrected code below shows how to fix this.

class Temperature:
def __init__(self, celsius):
self._celsius = celsius

@property
def celsius(self):
return self._celsius

@celsius.setter
def celsius(self, value):
self._celsius = value

@property
def fahrenheit(self):
return (self._celsius * 9/5) + 32

temp = Temperature(25)
temp.celsius = 30
print(temp.fahrenheit) # Outputs: 86.0

The fix is to implement a setter method using the @celsius.setter decorator. This method defines how to handle assignments to the celsius property, updating the internal _celsius attribute with the new value. This gives you explicit control over how the property is modified, turning it from a read-only attribute into a writable one.

  • Watch for this AttributeError whenever you need to make a previously read-only property updatable.

Real-world applications

Beyond the syntax and bug fixes, methods are the building blocks for practical tools like text analyzers and file size converters.

Using instance methods for text analysis

Instance methods are perfect for building tools that operate on specific data, like a text analyzer designed to process a unique string.

class TextAnalyzer:
def __init__(self, text):
self.text = text.lower()

def most_common_word(self):
words = self.text.split()
return max(set(words), key=words.count)

analyzer = TextAnalyzer("Python is amazing. Python is powerful.")
print(f"Most common word: {analyzer.most_common_word()}")

The TextAnalyzer class is initialized with a string, which it immediately converts to lowercase using text.lower() for case-insensitive analysis. The most_common_word method then finds the most frequent word in that text.

  • First, it uses split() to break the stored text into a list of individual words.
  • It then cleverly finds the most frequent one using max(). The key=words.count argument tells max() to evaluate each unique word from the set() based on its frequency in the original word list.

Creating a file size converter with @staticmethod

Since static methods don't need access to instance or class data, they're great for building standalone utility functions like a file size converter.

class FileSizeConverter:
@staticmethod
def bytes_to_mb(size_in_bytes):
return size_in_bytes / (1024 * 1024)

file_size = 1572864 # bytes
print(f"{FileSizeConverter.bytes_to_mb(file_size):.2f} MB")

The FileSizeConverter class neatly bundles the bytes_to_mb function. This approach keeps related logic organized without requiring an object to be created.

  • The @staticmethod decorator lets you call bytes_to_mb directly on the class, so you don't need an instance.
  • It takes a number of bytes and converts it to megabytes by dividing by 1024 * 1024.
  • The final print call uses an f-string with :.2f to format the output as a clean, two-decimal-place number.

Get started with Replit

Put these methods into practice by building a real tool. Tell Replit Agent: "Create a text analysis tool that counts word frequency" or "Build a unit converter with static methods for different measurements."

The Agent writes the code, tests for errors, and deploys the app for you. Start building with Replit.

Get started free

Create and deploy websites, automations, internal tools, data pipelines and more in any programming language without setup, downloads or extra tools. All in a single cloud workspace with AI built in.

Get started free

Create and deploy websites, automations, internal tools, data pipelines and more in any programming language without setup, downloads or extra tools. All in a single cloud workspace with AI built in.