Understanding Python Decorators: Function, Class, and Multi‑Layer Decorators
This article explains the concept, syntax, and practical examples of Python decorators—including function decorators, class‑based decorators, multi‑layer decorators, and class‑as‑decorator patterns—providing clear code snippets and execution results to help readers master decorator usage.
1. Function Decorators
A function decorator is a special wrapper function that receives another function as its argument, defines an inner function that can execute code before, after, or around the original call, and finally returns that inner function, thereby modifying the original function’s behavior.
Definition Syntax
<code>@decoratorName
def originalFunction(*args, **kwargs):
# function body
</code>Explanation of the Syntax
The decorator is declared with the @ symbol.
decoratorName must refer to an existing closure function that meets several requirements: it accepts a function object as its sole parameter, defines a nested function that calls the passed‑in function, forwards the original arguments, and returns the nested function.
The nested function must accept the same parameters as the original function (excluding the original function itself) and return a value compatible with the original function’s return type.
2. Class‑Based Function Decorators
Beyond decorating functions, a decorator can also be applied to a class. In this case the class name is passed to the decorator function, which creates a wrapper class (e.g., wrapClass ) that holds an instance of the original class and forwards method calls, optionally adding extra logic.
Example 1
<code>def decorateFunction(fun, *a, **k):
class wrapClass():
def __init__(self, *a, **k):
self.wrappedClass = fun(*a, **k)
def fun1(self, *a, **k):
print("准备调用被装饰类的方法fun1")
self.wrappedClass.fun1(*a, **k)
print("调用被装饰类的方法fun1完成")
return wrapClass
@decorateFunction
class wrappedClass:
def __init__(self, *a, **k):
print("我是被装饰类的构造方法")
if a: print("构造方法存在位置参数:", a)
if k: print("构造方法存在关键字参数:", k)
print("被装饰类构造方法执行完毕")
def fun1(self, *a, **k):
print("我是被装饰类的fun1方法")
if a: print("fun1存在位置参数:", a)
if k: print("fun1存在关键字参数:", k)
print("被装饰类fun1方法执行完毕")
def fun2(self, *a, **k):
print("我是被装饰类的fun2方法")
</code>Running the code shows that fun1 works because it is explicitly wrapped, while fun2 raises AttributeError because it was not re‑exposed in the wrapper.
Example 2 – Dynamic Method Forwarding
<code>def decorateFunction(fun, *a, **k):
class wrapClass():
def __init__(self, *a, **k):
self.wrappedClass = fun(*a, **k)
self.decorate()
def fun1(self, *a, **k):
print("准备调用被装饰类的方法fun1")
self.wrappedClass.fun1(*a, **k)
print("调用被装饰类的方法fun1完成")
def decorate(self):
for m in dir(self.wrappedClass):
if not m.startswith('_') and m != 'fun1':
fn = getattr(self.wrappedClass, m)
if callable(fn):
setattr(self, m, fn)
return wrapClass
</code>This version uses setattr to copy any missing methods from the original class, allowing fun2 to be called without explicit re‑definition.
3. Class Decorators for Functions
A class can serve as a decorator for a function by storing the target function as an instance attribute and implementing __call__ to execute additional logic before delegating to the original function.
<code>class decorateClass:
def __init__(self, fun):
self.fun = fun
def __call__(self, *a, **k):
print("执行被装饰函数")
return self.fun(*a, **k)
@decorateClass
def fun(*a, **k):
print(f"我是函数fun, 带参数:", a, k)
</code>Calling fun('funcation1', a=1, b=2) prints the decorator message followed by the function’s own output.
4. Class‑as‑Class Decorators
When both the decorator and the target are classes, the decorator class must implement __init__ (receiving the class to be wrapped) and __call__ (instantiating and returning the wrapped class). Inside __init__ a new subclass ( wrapClass ) is defined that inherits from the original class and can extend its __init__ method.
<code>class decorateClass:
def __init__(self, wrapedClass, *a, **k):
print("准备执行装饰类初始化")
class wrapClass(wrapedClass):
def __init__(self, *a, **k):
print(f"初始化被封装类实例开始,位置参数包括:{a}, 关键字参数为{k}")
super().__init__(*a, **k)
print("初始化被封装类实例结束")
self.wrapedClass = wrapClass
print("装饰类初始化完成")
def __call__(self, *a, **k):
print("被装饰类对象初始化开始")
obj = self.wrapedClass(*a, **k)
print("被装饰类对象初始化结束")
return obj
@decorateClass
class car:
def __init__(self, type, weight, cost):
print("class car __init__ start...")
self.type = type
self.weight = weight
self.cost = cost
self.distance = 0
print("class car __init__ end.")
def driver(self, distance):
self.distance += distance
print(f"{self.type}已经累计行驶了{self.distance}公里")
c = car('爱丽舍', '1.2吨', 8)
c.driver(10)
c.driver(110)
</code>The execution output demonstrates the decorator’s initialization messages, the wrapped class’s constructor calls, and the cumulative distance updates.
5. Summary
The article systematically introduces four categories of Python decorators—function‑as‑function, class‑as‑function, function‑as‑class, and class‑as‑class—detailing their implementation steps, key requirements, and concrete code examples, thereby providing readers with a comprehensive understanding of how to create and apply decorators in Python.
Python Programming Learning Circle
A global community of Chinese Python developers offering technical articles, columns, original video tutorials, and problem sets. Topics include web full‑stack development, web scraping, data analysis, natural language processing, image processing, machine learning, automated testing, DevOps automation, and big data.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.