Class decorator
- Python course
- Advanced
- Lesson 2/83
- 5 min
Learn class-based decorators.
Class decorator
A class decorator makes a class callable through the __call__ method and uses that class as a decorator instead of a function. The instance behaves like a function.
The advantage: it can hold state while wrapping. For example, it can count how many times it was called in an instance attribute. The shape is:
class Counter:
def __init__(self, fn):
self.fn = fn
self.count = 0
def __call__(self, *args):
self.count += 1
return self.fn(*args)A function decorated with @Counter is now a Counter instance; fn.count gives the call count.
Tracking state with a class decorator
The strength of class decorators is that they can hold state. You keep call counts, caches or timestamps in instance attributes.
Example: each call increments a counter and returns the result. If square(x) decorated with @Counter is called three times, square.count becomes 3.
Inside, self.fn(*args) runs the original function; self.count += 1 updates the counter. State stays on the instance; no global variable is needed.
Practice Call counter with a class decorator
Write a class decorator named Counter. Its __init__(self, fn) stores the function on self.fn and sets self.count to 0. Its __call__(self, *args) increments self.count each call and returns self.fn(*args). Decorate square(x) with @Counter so it returns x * x. Call square(3), square(4) and square(5); end with print(square.count).
Starter code
# Counter: class decorator with __init__ and __call__
# __init__ should hold fn and the count value
# __call__ should bump count and call fn
@Counter
def square(x):
return x * x
square(3)
square(4)
square(5)
print(square.count)Sample solution
class Counter:
def __init__(self, fn):
self.fn = fn
self.count = 0
def __call__(self, *args):
self.count += 1
return self.fn(*args)
@Counter
def square(x):
return x * x
square(3)
square(4)
square(5)
print(square.count)Expected output
3
Questions and answers
Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.
1 The call method in a class decorator
class Counter:
def __init__(self, fn):
self.fn = fn
self.count = 0
def ____(self, *args):
self.count += 1
return self.fn(*args)
class Counter:
def __init__(self, fn):
self.fn = fn
self.count = 0
def __call__(self, *args):
self.count += 1
return self.fn(*args)
Explanation: The __call__ method makes an instance callable; that is what gives the decorator behavior.
2 Where does a class decorator store call info?
- In a global variable
- In an instance attribute (like self.count) Correct answer
- In a local variable
- In a module-level constant
Explanation: A class decorator stores state in self-prefixed instance attributes; each instance has its own counter.
3 Match the class decorator pieces
| Term | Meaning |
|---|---|
__init__(self, fn) |
Holds the original function |
__call__(self, *args) |
Runs when called |
self.count |
State attribute |
self.fn(*args) |
Calls the original function |