Python
staticmethod
error
debugging
programming

'staticmethod' object is not callable

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

The error "'staticmethod' object is not callable" appears when Python code tries to call the staticmethod descriptor itself instead of the function bound through class attribute access. This usually happens when decorators are stacked incorrectly or when a method is accessed through __dict__ and bypasses descriptor behavior. The fix is to call the method through the class or instance name and verify decorator placement.

What @staticmethod Actually Does

@staticmethod wraps a function in a descriptor object. When you access MyClass.method, Python resolves the descriptor and returns the original function without injecting self or cls. If you access the raw descriptor directly, you get a staticmethod object, which is not directly callable.

python
1class MathUtils:
2    @staticmethod
3    def add(a, b):
4        return a + b
5
6print(MathUtils.add(2, 3))
7obj = MathUtils()
8print(obj.add(4, 5))

Both calls work because descriptor resolution happens through normal attribute access.

A common failure path is touching __dict__ directly.

python
1class Demo:
2    @staticmethod
3    def ping():
4        return "ok"
5
6raw = Demo.__dict__["ping"]
7print(type(raw))
8# print(raw())  # This would raise the staticmethod object not callable error
9
10# Correct way when you have the descriptor
11print(raw.__get__(None, Demo)())

In ordinary application code, avoid raw descriptor access unless you are doing introspection tooling.

Correct Decorator Order and Method Access

Decorator order matters when combining @staticmethod with custom decorators. If your decorator expects a function but receives a descriptor, it can break callability.

python
1def traced(fn):
2    def wrapper(*args, **kwargs):
3        print("calling", fn.__name__)
4        return fn(*args, **kwargs)
5    return wrapper
6
7class Service:
8    @staticmethod
9    @traced
10    def run_task(name):
11        return f"task:{name}"
12
13print(Service.run_task("cleanup"))

If you reverse incompatible decorators, the wrapped object may no longer behave as expected. Keep unit tests around decorator-heavy utilities so refactors do not silently change call semantics.

Choosing Between Static, Class, and Instance Methods

Use @staticmethod when logic belongs conceptually to a class namespace but does not need instance or class state. If method behavior depends on class-level configuration, use @classmethod instead. If method needs object state, use normal instance methods.

python
1class Parser:
2    default_sep = ","
3
4    @staticmethod
5    def split_fixed(text):
6        return text.split(",")
7
8    @classmethod
9    def split_with_default(cls, text):
10        return text.split(cls.default_sep)
11
12    def __init__(self, sep):
13        self.sep = sep
14
15    def split_with_instance(self, text):
16        return text.split(self.sep)

Selecting the right method type reduces confusion and eliminates many descriptor-related bugs.

Testing Patterns That Catch Descriptor Mistakes

Descriptor bugs often appear only after refactoring, so automated tests are the best safety net. Write tests that call methods through class access and instance access, and add one introspection test if your framework inspects class dictionaries. This prevents future edits from silently changing call behavior.

python
1import unittest
2
3class MathUtils:
4    @staticmethod
5    def add(a, b):
6        return a + b
7
8class StaticMethodTests(unittest.TestCase):
9    def test_class_call(self):
10        self.assertEqual(MathUtils.add(2, 3), 5)
11
12    def test_instance_call(self):
13        self.assertEqual(MathUtils().add(4, 1), 5)
14
15    def test_descriptor_unwrap(self):
16        raw = MathUtils.__dict__["add"]
17        fn = raw.__get__(None, MathUtils)
18        self.assertEqual(fn(3, 2), 5)
19
20if __name__ == "__main__":
21    unittest.main()

These tests document intended behavior and make decorator regressions obvious during continuous integration.

Common Pitfalls

  • Calling descriptors pulled from __dict__ directly instead of using attribute access.
  • Applying decorators in an order that passes a staticmethod descriptor where a function is expected.
  • Using @staticmethod for behavior that actually needs class configuration.
  • Renaming methods without updating tests that validate call paths.
  • Overusing static methods for unrelated utility logic better placed in separate modules.

Summary

  • @staticmethod creates a descriptor resolved through class or instance attribute access.
  • The raw staticmethod object is not the callable function you want.
  • Use normal access like MyClass.method() for reliable behavior.
  • Validate decorator order when stacking custom wrappers with @staticmethod.
  • Pick static, class, or instance methods based on required state access.

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.