Python 装饰器模式 Decorate Patter
有勇气的牛排
31
Python
2025-07-28 22:45:50
Python 装饰器模式 Decorate Patter
1 前言
1.1 定义
如果装饰器有多个,则从下往上依次执行。
1.1.1 设计模式角度
装饰器模式是一种结构型设计模式,允许在不修改原始类代码的前提下,动态地扩展对象的功能。
1.1.2 Python 角度
Python装饰器是一个接收函数/类作为参数,返回一个增强后的函数/类的高阶函数。
1.2 优缺点
优点:
- 不修改原函数的情况下添加功能
- 支持灵活组合
- 更加模块化、可重用
缺点:
- 嵌套函数较多,初学者阅读难度稍大
- 错误处理复杂时调试不易
- 不当使用,可能影响函数签名和文档信息
2 基本写法
def my_decorate(func):
def wrapper(*args, **kwargs):
print("开始执行")
result = func(*args, **kwargs)
print("结束执行")
return result
return wrapper
@my_decorate
def greet(name):
print(f"你好:{name}")
greet("有勇气的牛排")

3 常见场景
3.1 权限校验
def require_admin(func):
def wrapper(user_role, user_id, *args, **kwargs):
if user_role != 'admin':
print('无权限')
else:
return func(user_role, user_id, *args, **kwargs)
return wrapper
@require_admin
def get_user_info(user_role, user_id):
print('正在获取用户信息')
get_user_info("admin", 1)
get_user_info("guest", 2)
3.2 耗时统计
import time
def func_run_time(func):
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
print("函数运行时间:%s" % (end_time - start_time))
return result
return wrapper
@func_run_time
def test():
time.sleep(1)
test()

3.3 类装饰器
类也可以作为装饰器使用,可用于更复杂的状态维护。
这里需要使用到魔法方法__call__
,这个方法可以让类的调用与函数一样。
class Log:
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
print('开始执行')
result = self.func(*args, **kwargs)
return result
@Log
def greet(name):
print(f"你好:{name}")
greet("有勇气的牛排")
<h1><a id="Python__Decorate_Patter_0"></a>Python 装饰器模式 Decorate Patter</h1>
<h2><a id="1__2"></a>1 前言</h2>
<h3><a id="11__4"></a>1.1 定义</h3>
<p>如果装饰器有多个,则从下往上依次执行。</p>
<h4><a id="111__8"></a>1.1.1 设计模式角度</h4>
<p>装饰器模式是一种<strong>结构型设计模式</strong>,允许在<strong>不修改原始类代码</strong>的前提下,<strong>动态地扩展对象的功能</strong>。</p>
<h4><a id="112_Python__12"></a>1.1.2 Python 角度</h4>
<p>Python装饰器是一个<strong>接收函数/类作为参数</strong>,<strong>返回一个增强后的函数/类</strong>的<strong>高阶函数</strong>。</p>
<h3><a id="12__16"></a>1.2 优缺点</h3>
<p>优点:</p>
<ul>
<li>不修改原函数的情况下添加功能</li>
<li>支持灵活组合</li>
<li>更加模块化、可重用</li>
</ul>
<p>缺点:</p>
<ul>
<li>嵌套函数较多,初学者阅读难度稍大</li>
<li>错误处理复杂时调试不易</li>
<li>不当使用,可能影响函数签名和文档信息</li>
</ul>
<h2><a id="2__32"></a>2 基本写法</h2>
<pre><div class="hljs"><code class="lang-python"><span class="hljs-comment"># -*- coding: utf-8 -*-</span>
<span class="hljs-keyword">def</span> <span class="hljs-title function_">my_decorate</span>(<span class="hljs-params">func</span>):
<span class="hljs-keyword">def</span> <span class="hljs-title function_">wrapper</span>(<span class="hljs-params">*args, **kwargs</span>):
<span class="hljs-built_in">print</span>(<span class="hljs-string">"开始执行"</span>)
result = func(*args, **kwargs)
<span class="hljs-built_in">print</span>(<span class="hljs-string">"结束执行"</span>)
<span class="hljs-keyword">return</span> result
<span class="hljs-keyword">return</span> wrapper
<span class="hljs-meta">@my_decorate</span>
<span class="hljs-keyword">def</span> <span class="hljs-title function_">greet</span>(<span class="hljs-params">name</span>):
<span class="hljs-built_in">print</span>(<span class="hljs-string">f"你好:<span class="hljs-subst">{name}</span>"</span>)
greet(<span class="hljs-string">"有勇气的牛排"</span>)
<span class="hljs-comment"># 等价写法</span>
<span class="hljs-comment"># greet = my_decorate(greet)</span>
<span class="hljs-comment"># greet("有勇气的牛排")</span>
</code></div></pre>
<p><img src="https://static.couragesteak.com/article/d32f9c8954bbb099445d3c14627ae8ad.png" alt="image.png" /></p>
<h2><a id="3__60"></a>3 常见场景</h2>
<h3><a id="31__62"></a>3.1 权限校验</h3>
<pre><div class="hljs"><code class="lang-python"><span class="hljs-comment"># -*- coding: utf-8 -*-</span>
<span class="hljs-keyword">def</span> <span class="hljs-title function_">require_admin</span>(<span class="hljs-params">func</span>):
<span class="hljs-keyword">def</span> <span class="hljs-title function_">wrapper</span>(<span class="hljs-params">user_role, user_id, *args, **kwargs</span>):
<span class="hljs-keyword">if</span> user_role != <span class="hljs-string">'admin'</span>:
<span class="hljs-built_in">print</span>(<span class="hljs-string">'无权限'</span>)
<span class="hljs-keyword">else</span>:
<span class="hljs-keyword">return</span> func(user_role, user_id, *args, **kwargs)
<span class="hljs-keyword">return</span> wrapper
<span class="hljs-meta">@require_admin</span>
<span class="hljs-keyword">def</span> <span class="hljs-title function_">get_user_info</span>(<span class="hljs-params">user_role, user_id</span>):
<span class="hljs-built_in">print</span>(<span class="hljs-string">'正在获取用户信息'</span>)
get_user_info(<span class="hljs-string">"admin"</span>, <span class="hljs-number">1</span>)
get_user_info(<span class="hljs-string">"guest"</span>, <span class="hljs-number">2</span>)
</code></div></pre>
<h3><a id="32__85"></a>3.2 耗时统计</h3>
<pre><div class="hljs"><code class="lang-python"><span class="hljs-comment"># -*- coding: utf-8 -*-</span>
<span class="hljs-keyword">import</span> time
<span class="hljs-keyword">def</span> <span class="hljs-title function_">func_run_time</span>(<span class="hljs-params">func</span>):
<span class="hljs-keyword">def</span> <span class="hljs-title function_">wrapper</span>(<span class="hljs-params">*args, **kwargs</span>):
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
<span class="hljs-built_in">print</span>(<span class="hljs-string">"函数运行时间:%s"</span> % (end_time - start_time))
<span class="hljs-keyword">return</span> result
<span class="hljs-keyword">return</span> wrapper
<span class="hljs-meta">@func_run_time</span>
<span class="hljs-keyword">def</span> <span class="hljs-title function_">test</span>():
time.sleep(<span class="hljs-number">1</span>)
test()
</code></div></pre>
<p><img src="https://static.couragesteak.com/article/f7953928f14cf8c051c8f3c9403dd305.png" alt="image.png" /></p>
<h3><a id="33__110"></a>3.3 类装饰器</h3>
<p>类也可以作为装饰器使用,可用于更复杂的状态维护。</p>
<p>这里需要使用到魔法方法<code>__call__</code>,这个方法可以让类的调用与函数一样。</p>
<pre><div class="hljs"><code class="lang-python"><span class="hljs-comment"># -*- coding: utf-8 -*-</span>
<span class="hljs-keyword">class</span> <span class="hljs-title class_">Log</span>:
<span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self, func</span>):
self.func = func
<span class="hljs-keyword">def</span> <span class="hljs-title function_">__call__</span>(<span class="hljs-params">self, *args, **kwargs</span>):
<span class="hljs-built_in">print</span>(<span class="hljs-string">'开始执行'</span>)
result = self.func(*args, **kwargs)
<span class="hljs-keyword">return</span> result
<span class="hljs-meta">@Log</span>
<span class="hljs-keyword">def</span> <span class="hljs-title function_">greet</span>(<span class="hljs-params">name</span>):
<span class="hljs-built_in">print</span>(<span class="hljs-string">f"你好:<span class="hljs-subst">{name}</span>"</span>)
greet(<span class="hljs-string">"有勇气的牛排"</span>)
</code></div></pre>
评论区