Python装饰器用法实例总结
<p><strong>一、装饰器是什么</strong></p><p>python的装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。简单的说装饰器就是一个用来返回函数的函数。</p>
<p>它经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景。装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量与函数功能本身无关的雷同代码并继续重用。</p>
<p>概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能。</p>
<p><strong>二、为什么需要装饰器</strong></p>
<p>1、先来看一个简单例子:</p>
<div class="jb51code">
<div>
<div id="highlighter_783570" class="syntaxhighlighterpy">
<div class="toolbar">?</div>
<table border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td class="gutter">
<div class="line number1 index0 alt2">1</div>
<div class="line number2 index1 alt1">2</div>
</td>
<td class="code">
<div class="container">
<div class="line number1 index0 alt2"><code class="py keyword">def</code> <code class="py plain">foo():</code></div>
<div class="line number2 index1 alt1"><code class="py functions">print</code><code class="py plain">(</code><code class="py string">'i am foo'</code><code class="py plain">)</code></div>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<p>2、增加需求</p>
<p>现在有一个新的需求,希望可以记录下函数的执行日志,于是在代码中添加日志代码:</p>
<div class="jb51code">
<div>
<div id="highlighter_344883" class="syntaxhighlighterpy">
<div class="toolbar">?</div>
<table border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td class="gutter">
<div class="line number1 index0 alt2">1</div>
<div class="line number2 index1 alt1">2</div>
<div class="line number3 index2 alt2">3</div>
</td>
<td class="code">
<div class="container">
<div class="line number1 index0 alt2"><code class="py keyword">def</code> <code class="py plain">foo():</code></div>
<div class="line number2 index1 alt1"><code class="py spaces"> </code><code class="py functions">print</code><code class="py plain">(</code><code class="py string">'i am foo'</code><code class="py plain">)</code></div>
<div class="line number3 index2 alt2"><code class="py spaces"> </code><code class="py functions">print</code><code class="py plain">(</code><code class="py string">"foo is running"</code><code class="py plain">)</code></div>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<p>3、又有需求</p>
<p>假设现在有100个函数需要增加这个需求,并且后续可能还要对这一百个函数都增加执行前打印日志的需求,怎么办?还一个个改吗?</p>
<p>当然不了,这样会造成大量雷同的代码,为了减少重复写代码,我们可以这样做,重新定义一个函数:专门处理日志 ,日志处理完之后再执行真正的业务代码。</p>
<div class="jb51code">
<div>
<div id="highlighter_197629" class="syntaxhighlighterpy">
<div class="toolbar">?</div>
<table border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td class="gutter">
<div class="line number1 index0 alt2">1</div>
<div class="line number2 index1 alt1">2</div>
<div class="line number3 index2 alt2">3</div>
<div class="line number4 index3 alt1">4</div>
<div class="line number5 index4 alt2">5</div>
<div class="line number6 index5 alt1">6</div>
<div class="line number7 index6 alt2">7</div>
<div class="line number8 index7 alt1">8</div>
<div class="line number9 index8 alt2">9</div>
</td>
<td class="code">
<div class="container">
<div class="line number1 index0 alt2"><code class="py keyword">def</code> <code class="py plain">use_logging(func):</code></div>
<div class="line number2 index1 alt1"><code class="py spaces"> </code><code class="py functions">print</code><code class="py plain">(</code><code class="py string">"%s is running"</code> <code class="py keyword">%</code> <code class="py plain">func.__name__)</code></div>
<div class="line number3 index2 alt2"><code class="py spaces"> </code><code class="py plain">func()</code></div>
<div class="line number4 index3 alt1"><code class="py keyword">def</code> <code class="py plain">bar():</code></div>
<div class="line number5 index4 alt2"><code class="py spaces"> </code><code class="py functions">print</code><code class="py plain">(</code><code class="py string">'i am bar'</code><code class="py plain">)</code></div>
<div class="line number6 index5 alt1"><code class="py plain">use_logging(bar)</code></div>
<div class="line number7 index6 alt2"><code class="py comments">#result:</code></div>
<div class="line number8 index7 alt1"><code class="py comments">#bar is running</code></div>
<div class="line number9 index8 alt2"><code class="py comments">#i am bar</code></div>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<p>通过以上use_logging函数我们增加了日志功能,不管以后有多少函数需要增加日志或者修改日志的格式我们只需要修改use_logging函数,并执行use_logging(被装饰的函数)就达到了我们想要的效果。</p>
<div class="jb51code">
<div>
<div id="highlighter_89013" class="syntaxhighlighterpy">
<div class="toolbar">?</div>
<table border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td class="gutter">
<div class="line number1 index0 alt2">1</div>
<div class="line number2 index1 alt1">2</div>
<div class="line number3 index2 alt2">3</div>
<div class="line number4 index3 alt1">4</div>
<div class="line number5 index4 alt2">5</div>
<div class="line number6 index5 alt1">6</div>
<div class="line number7 index6 alt2">7</div>
</td>
<td class="code">
<div class="container">
<div class="line number1 index0 alt2"><code class="py keyword">def</code> <code class="py plain">use_logging(func):</code></div>
<div class="line number2 index1 alt1"><code class="py spaces"> </code><code class="py functions">print</code><code class="py plain">(</code><code class="py string">"%s is running"</code> <code class="py keyword">%</code> <code class="py plain">func.__name__)</code></div>
<div class="line number3 index2 alt2"><code class="py spaces"> </code><code class="py keyword">return</code> <code class="py plain">func</code></div>
<div class="line number4 index3 alt1"><code class="py decorator">@use_logging</code></div>
<div class="line number5 index4 alt2"><code class="py keyword">def</code> <code class="py plain">bar():</code></div>
<div class="line number6 index5 alt1"><code class="py spaces"> </code><code class="py functions">print</code><code class="py plain">(</code><code class="py string">'i am bar'</code><code class="py plain">)</code></div>
<div class="line number7 index6 alt2"><code class="py plain">bar()</code></div>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<p><strong>三、基础装饰器入门</strong></p>
<p>1、装饰器语法糖</p>
<p>python提供了@符号作为装饰器的语法糖,使我们更方便的应用装饰函数。但使用语法糖要求装饰函数必须return一个函数对象。因此我们将上面的func函数使用内嵌函数包裹并return。</p>
<p>装饰器相当于执行了装饰函数use_loggin后又返回被装饰函数bar,因此bar()被调用的时候相当于执行了两个函数。等价于use_logging(bar)()</p>
<div class="jb51code">
<div>
<div id="highlighter_957595" class="syntaxhighlighterpy">
<div class="toolbar">?</div>
<table border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td class="gutter">
<div class="line number1 index0 alt2">1</div>
<div class="line number2 index1 alt1">2</div>
<div class="line number3 index2 alt2">3</div>
<div class="line number4 index3 alt1">4</div>
<div class="line number5 index4 alt2">5</div>
<div class="line number6 index5 alt1">6</div>
<div class="line number7 index6 alt2">7</div>
<div class="line number8 index7 alt1">8</div>
<div class="line number9 index8 alt2">9</div>
</td>
<td class="code">
<div class="container">
<div class="line number1 index0 alt2"><code class="py keyword">def</code> <code class="py plain">use_logging(func):</code></div>
<div class="line number2 index1 alt1"><code class="py spaces"> </code><code class="py keyword">def</code> <code class="py plain">_deco():</code></div>
<div class="line number3 index2 alt2"><code class="py spaces"> </code><code class="py functions">print</code><code class="py plain">(</code><code class="py string">"%s is running"</code> <code class="py keyword">%</code> <code class="py plain">func.__name__)</code></div>
<div class="line number4 index3 alt1"><code class="py spaces"> </code><code class="py plain">func()</code></div>
<div class="line number5 index4 alt2"><code class="py spaces"> </code><code class="py keyword">return</code> <code class="py plain">_deco</code></div>
<div class="line number6 index5 alt1"><code class="py decorator">@use_logging</code></div>
<div class="line number7 index6 alt2"><code class="py keyword">def</code> <code class="py plain">bar():</code></div>
<div class="line number8 index7 alt1"><code class="py spaces"> </code><code class="py functions">print</code><code class="py plain">(</code><code class="py string">'i am bar'</code><code class="py plain">)</code></div>
<div class="line number9 index8 alt2"><code class="py plain">bar()</code></div>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<p>2、对带参数的函数进行装饰</p>
<p>现在我们的参数需要传入两个参数并计算值,因此我们需要对内层函数进行改动传入我们的两个参数a和b,等价于use_logging(bar)(1,2)</p>
<div class="jb51code">
<div>
<div id="highlighter_91330" class="syntaxhighlighterpy">
<div class="toolbar">?</div>
<table border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td class="gutter">
<div class="line number1 index0 alt2">1</div>
<div class="line number2 index1 alt1">2</div>
<div class="line number3 index2 alt2">3</div>
<div class="line number4 index3 alt1">4</div>
<div class="line number5 index4 alt2">5</div>
<div class="line number6 index5 alt1">6</div>
<div class="line number7 index6 alt2">7</div>
<div class="line number8 index7 alt1">8</div>
<div class="line number9 index8 alt2">9</div>
</td>
<td class="code">
<div class="container">
<div class="line number1 index0 alt2"><code class="py keyword">def</code> <code class="py plain">use_logging(func):</code></div>
<div class="line number2 index1 alt1"><code class="py spaces"> </code><code class="py keyword">def</code> <code class="py plain">_deco(a,b):</code></div>
<div class="line number3 index2 alt2"><code class="py spaces"> </code><code class="py functions">print</code><code class="py plain">(</code><code class="py string">"%s is running"</code> <code class="py keyword">%</code> <code class="py plain">func.__name__)</code></div>
<div class="line number4 index3 alt1"><code class="py spaces"> </code><code class="py plain">func(a,b)</code></div>
<div class="line number5 index4 alt2"><code class="py spaces"> </code><code class="py keyword">return</code> <code class="py plain">_deco</code></div>
<div class="line number6 index5 alt1"><code class="py decorator">@use_logging</code></div>
<div class="line number7 index6 alt2"><code class="py keyword">def</code> <code class="py plain">bar(a,b):</code></div>
<div class="line number8 index7 alt1"><code class="py spaces"> </code><code class="py functions">print</code><code class="py plain">(</code><code class="py string">'i am bar:%s'</code><code class="py keyword">%</code><code class="py plain">(a</code><code class="py keyword">+</code><code class="py plain">b))</code></div>
<div class="line number9 index8 alt2"><code class="py plain">bar(</code><code class="py value">1</code><code class="py plain">,</code><code class="py value">2</code><code class="py plain">)</code></div>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<p>我们装饰的函数可能参数的个数和类型都不一样,每一次我们都需要对装饰器做修改吗?这样做当然是不科学的,因此我们使用python的变长参数*args和**kwargs来解决我们的参数问题。</p>
<p>3、函数参数数量不确定</p>
<p><strong>不带参数装饰器版本,这个格式适用于不带参数的装饰器。</strong></p>
<p>经过以下修改我们已经适应了各种长度和类型的参数。这个版本的装饰器已经可以任意类型的无参数函数。</p>
<div class="jb51code">
<div>
<div id="highlighter_205004" class="syntaxhighlighterpy">
<div class="toolbar">?</div>
<table border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td class="gutter">
<div class="line number1 index0 alt2">1</div>
<div class="line number2 index1 alt1">2</div>
<div class="line number3 index2 alt2">3</div>
<div class="line number4 index3 alt1">4</div>
<div class="line number5 index4 alt2">5</div>
<div class="line number6 index5 alt1">6</div>
<div class="line number7 index6 alt2">7</div>
<div class="line number8 index7 alt1">8</div>
<div class="line number9 index8 alt2">9</div>
<div class="line number10 index9 alt1">10</div>
<div class="line number11 index10 alt2">11</div>
<div class="line number12 index11 alt1">12</div>
<div class="line number13 index12 alt2">13</div>
</td>
<td class="code">
<div class="container">
<div class="line number1 index0 alt2"><code class="py keyword">def</code> <code class="py plain">use_logging(func):</code></div>
<div class="line number2 index1 alt1"><code class="py spaces"> </code><code class="py keyword">def</code> <code class="py plain">_deco(</code><code class="py keyword">*</code><code class="py plain">args,</code><code class="py keyword">*</code><code class="py keyword">*</code><code class="py plain">kwargs):</code></div>
<div class="line number3 index2 alt2"><code class="py spaces"> </code><code class="py functions">print</code><code class="py plain">(</code><code class="py string">"%s is running"</code> <code class="py keyword">%</code> <code class="py plain">func.__name__)</code></div>
<div class="line number4 index3 alt1"><code class="py spaces"> </code><code class="py plain">func(</code><code class="py keyword">*</code><code class="py plain">args,</code><code class="py keyword">*</code><code class="py keyword">*</code><code class="py plain">kwargs)</code></div>
<div class="line number5 index4 alt2"><code class="py spaces"> </code><code class="py keyword">return</code> <code class="py plain">_deco</code></div>
<div class="line number6 index5 alt1"><code class="py decorator">@use_logging</code></div>
<div class="line number7 index6 alt2"><code class="py keyword">def</code> <code class="py plain">bar(a,b):</code></div>
<div class="line number8 index7 alt1"><code class="py spaces"> </code><code class="py functions">print</code><code class="py plain">(</code><code class="py string">'i am bar:%s'</code><code class="py keyword">%</code><code class="py plain">(a</code><code class="py keyword">+</code><code class="py plain">b))</code></div>
<div class="line number9 index8 alt2"><code class="py decorator">@use_logging</code></div>
<div class="line number10 index9 alt1"><code class="py keyword">def</code> <code class="py plain">foo(a,b,c):</code></div>
<div class="line number11 index10 alt2"><code class="py spaces"> </code><code class="py functions">print</code><code class="py plain">(</code><code class="py string">'i am bar:%s'</code><code class="py keyword">%</code><code class="py plain">(a</code><code class="py keyword">+</code><code class="py plain">b</code><code class="py keyword">+</code><code class="py plain">c))</code></div>
<div class="line number12 index11 alt1"><code class="py plain">bar(</code><code class="py value">1</code><code class="py plain">,</code><code class="py value">2</code><code class="py plain">)</code></div>
<div class="line number13 index12 alt2"><code class="py plain">foo(</code><code class="py value">1</code><code class="py plain">,</code><code class="py value">2</code><code class="py plain">,</code><code class="py value">3</code><code class="py plain">)</code></div>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<p>4、装饰器带参数</p>
<p><strong>带参数的装饰器,这个格式适用于带参数的装饰器。</strong></p>
<p>某些情况我们需要让装饰器带上参数,那就需要编写一个返回一个装饰器的高阶函数,写出来会更复杂。比如:</p>
<div class="jb51code">
<div>
<div id="highlighter_432662" class="syntaxhighlighterpy">
<div class="toolbar">?</div>
<table border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td class="gutter">
<div class="line number1 index0 alt2">1</div>
<div class="line number2 index1 alt1">2</div>
<div class="line number3 index2 alt2">3</div>
<div class="line number4 index3 alt1">4</div>
<div class="line number5 index4 alt2">5</div>
<div class="line number6 index5 alt1">6</div>
<div class="line number7 index6 alt2">7</div>
<div class="line number8 index7 alt1">8</div>
<div class="line number9 index8 alt2">9</div>
<div class="line number10 index9 alt1">10</div>
<div class="line number11 index10 alt2">11</div>
<div class="line number12 index11 alt1">12</div>
<div class="line number13 index12 alt2">13</div>
<div class="line number14 index13 alt1">14</div>
<div class="line number15 index14 alt2">15</div>
<div class="line number16 index15 alt1">16</div>
</td>
<td class="code">
<div class="container">
<div class="line number1 index0 alt2"><code class="py comments">#! /usr/bin/env python</code></div>
<div class="line number2 index1 alt1"><code class="py comments"># -*- coding:utf-8 -*-</code></div>
<div class="line number3 index2 alt2"><code class="py comments"># __author__ = "TKQ"</code></div>
<div class="line number4 index3 alt1"><code class="py keyword">def</code> <code class="py plain">use_logging(level):</code></div>
<div class="line number5 index4 alt2"><code class="py spaces"> </code><code class="py keyword">def</code> <code class="py plain">_deco(func):</code></div>
<div class="line number6 index5 alt1"><code class="py spaces"> </code><code class="py keyword">def</code> <code class="py plain">__deco(</code><code class="py keyword">*</code><code class="py plain">args, </code><code class="py keyword">*</code><code class="py keyword">*</code><code class="py plain">kwargs):</code></div>
<div class="line number7 index6 alt2"><code class="py spaces"> </code><code class="py keyword">if</code> <code class="py plain">level </code><code class="py keyword">=</code><code class="py keyword">=</code> <code class="py string">"warn"</code><code class="py plain">:</code></div>
<div class="line number8 index7 alt1"><code class="py spaces"> </code><code class="py functions">print</code> <code class="py string">"%s is running"</code> <code class="py keyword">%</code> <code class="py plain">func.__name__</code></div>
<div class="line number9 index8 alt2"><code class="py spaces"> </code><code class="py keyword">return</code> <code class="py plain">func(</code><code class="py keyword">*</code><code class="py plain">args, </code><code class="py keyword">*</code><code class="py keyword">*</code><code class="py plain">kwargs)</code></div>
<div class="line number10 index9 alt1"><code class="py spaces"> </code><code class="py keyword">return</code> <code class="py plain">__deco</code></div>
<div class="line number11 index10 alt2"><code class="py spaces"> </code><code class="py keyword">return</code> <code class="py plain">_deco</code></div>
<div class="line number12 index11 alt1"><code class="py decorator">@use_logging</code><code class="py plain">(level</code><code class="py keyword">=</code><code class="py string">"warn"</code><code class="py plain">)</code></div>
<div class="line number13 index12 alt2"><code class="py keyword">def</code> <code class="py plain">bar(a,b):</code></div>
<div class="line number14 index13 alt1"><code class="py spaces"> </code><code class="py functions">print</code><code class="py plain">(</code><code class="py string">'i am bar:%s'</code><code class="py keyword">%</code><code class="py plain">(a</code><code class="py keyword">+</code><code class="py plain">b))</code></div>
<div class="line number15 index14 alt2"><code class="py plain">bar(</code><code class="py value">1</code><code class="py plain">,</code><code class="py value">3</code><code class="py plain">)</code></div>
<div class="line number16 index15 alt1"><code class="py comments"># 等价于use_logging(level="warn")(bar)(1,3)</code></div>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<p>5、functools.wraps</p>
<p>使用装饰器极大地复用了代码,但是他有一个缺点就是原函数的元信息不见了,比如函数的docstring、__name__、参数列表,先看例子:</p>
<div class="jb51code">
<div>
<div id="highlighter_461527" class="syntaxhighlighterpy">
<div class="toolbar">?</div>
<table border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td class="gutter">
<div class="line number1 index0 alt2">1</div>
<div class="line number2 index1 alt1">2</div>
<div class="line number3 index2 alt2">3</div>
<div class="line number4 index3 alt1">4</div>
<div class="line number5 index4 alt2">5</div>
<div class="line number6 index5 alt1">6</div>
<div class="line number7 index6 alt2">7</div>
<div class="line number8 index7 alt1">8</div>
<div class="line number9 index8 alt2">9</div>
<div class="line number10 index9 alt1">10</div>
<div class="line number11 index10 alt2">11</div>
<div class="line number12 index11 alt1">12</div>
<div class="line number13 index12 alt2">13</div>
<div class="line number14 index13 alt1">14</div>
</td>
<td class="code">
<div class="container">
<div class="line number1 index0 alt2"><code class="py keyword">def</code> <code class="py plain">use_logging(func):</code></div>
<div class="line number2 index1 alt1"><code class="py spaces"> </code><code class="py keyword">def</code> <code class="py plain">_deco(</code><code class="py keyword">*</code><code class="py plain">args,</code><code class="py keyword">*</code><code class="py keyword">*</code><code class="py plain">kwargs):</code></div>
<div class="line number3 index2 alt2"><code class="py spaces"> </code><code class="py functions">print</code><code class="py plain">(</code><code class="py string">"%s is running"</code> <code class="py keyword">%</code> <code class="py plain">func.__name__)</code></div>
<div class="line number4 index3 alt1"><code class="py spaces"> </code><code class="py plain">func(</code><code class="py keyword">*</code><code class="py plain">args,</code><code class="py keyword">*</code><code class="py keyword">*</code><code class="py plain">kwargs)</code></div>
<div class="line number5 index4 alt2"><code class="py spaces"> </code><code class="py keyword">return</code> <code class="py plain">_deco</code></div>
<div class="line number6 index5 alt1"><code class="py decorator">@use_logging</code></div>
<div class="line number7 index6 alt2"><code class="py keyword">def</code> <code class="py plain">bar():</code></div>
<div class="line number8 index7 alt1"><code class="py spaces"> </code><code class="py functions">print</code><code class="py plain">(</code><code class="py string">'i am bar'</code><code class="py plain">)</code></div>
<div class="line number9 index8 alt2"><code class="py spaces"> </code><code class="py functions">print</code><code class="py plain">(bar.__name__)</code></div>
<div class="line number10 index9 alt1"><code class="py plain">bar()</code></div>
<div class="line number11 index10 alt2"><code class="py comments">#bar is running</code></div>
<div class="line number12 index11 alt1"><code class="py comments">#i am bar</code></div>
<div class="line number13 index12 alt2"><code class="py comments">#_deco</code></div>
<div class="line number14 index13 alt1"><code class="py comments">#函数名变为_deco而不是bar,这个情况在使用反射的特性的时候就会造成问题。因此引入了functools.wraps解决这个问题。</code></div>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<p>使用functools.wraps:</p>
<div class="jb51code">
<div>
<div id="highlighter_81242" class="syntaxhighlighterpy">
<div class="toolbar">?</div>
<table border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td class="gutter">
<div class="line number1 index0 alt2">1</div>
<div class="line number2 index1 alt1">2</div>
<div class="line number3 index2 alt2">3</div>
<div class="line number4 index3 alt1">4</div>
<div class="line number5 index4 alt2">5</div>
<div class="line number6 index5 alt1">6</div>
<div class="line number7 index6 alt2">7</div>
<div class="line number8 index7 alt1">8</div>
<div class="line number9 index8 alt2">9</div>
<div class="line number10 index9 alt1">10</div>
<div class="line number11 index10 alt2">11</div>
<div class="line number12 index11 alt1">12</div>
<div class="line number13 index12 alt2">13</div>
<div class="line number14 index13 alt1">14</div>
<div class="line number15 index14 alt2">15</div>
<div class="line number16 index15 alt1">16</div>
</td>
<td class="code">
<div class="container">
<div class="line number1 index0 alt2"><code class="py keyword">import</code> <code class="py plain">functools</code></div>
<div class="line number2 index1 alt1"><code class="py keyword">def</code> <code class="py plain">use_logging(func):</code></div>
<div class="line number3 index2 alt2"><code class="py spaces"> </code><code class="py decorator">@functools</code><code class="py plain">.wraps(func)</code></div>
<div class="line number4 index3 alt1"><code class="py spaces"> </code><code class="py keyword">def</code> <code class="py plain">_deco(</code><code class="py keyword">*</code><code class="py plain">args,</code><code class="py keyword">*</code><code class="py keyword">*</code><code class="py plain">kwargs):</code></div>
<div class="line number5 index4 alt2"><code class="py spaces"> </code><code class="py functions">print</code><code class="py plain">(</code><code class="py string">"%s is running"</code> <code class="py keyword">%</code> <code class="py plain">func.__name__)</code></div>
<div class="line number6 index5 alt1"><code class="py spaces"> </code><code class="py plain">func(</code><code class="py keyword">*</code><code class="py plain">args,</code><code class="py keyword">*</code><code class="py keyword">*</code><code class="py plain">kwargs)</code></div>
<div class="line number7 index6 alt2"><code class="py spaces"> </code><code class="py keyword">return</code> <code class="py plain">_deco</code></div>
<div class="line number8 index7 alt1"><code class="py decorator">@use_logging</code></div>
<div class="line number9 index8 alt2"><code class="py keyword">def</code> <code class="py plain">bar():</code></div>
<div class="line number10 index9 alt1"><code class="py spaces"> </code><code class="py functions">print</code><code class="py plain">(</code><code class="py string">'i am bar'</code><code class="py plain">)</code></div>
<div class="line number11 index10 alt2"><code class="py spaces"> </code><code class="py functions">print</code><code class="py plain">(bar.__name__)</code></div>
<div class="line number12 index11 alt1"><code class="py plain">bar()</code></div>
<div class="line number13 index12 alt2"><code class="py comments">#result:</code></div>
<div class="line number14 index13 alt1"><code class="py comments">#bar is running</code></div>
<div class="line number15 index14 alt2"><code class="py comments">#i am bar</code></div>
<div class="line number16 index15 alt1"><code class="py comments">#bar ,这个结果是我们想要的。OK啦!</code></div>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<p>6、实现带参数和不带参数的装饰器自适应</p>
<div class="jb51code">
<div>
<div id="highlighter_949557" class="syntaxhighlighterpy">
<div class="toolbar">?</div>
<table border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td class="gutter">
<div class="line number1 index0 alt2">1</div>
<div class="line number2 index1 alt1">2</div>
<div class="line number3 index2 alt2">3</div>
<div class="line number4 index3 alt1">4</div>
<div class="line number5 index4 alt2">5</div>
<div class="line number6 index5 alt1">6</div>
<div class="line number7 index6 alt2">7</div>
<div class="line number8 index7 alt1">8</div>
<div class="line number9 index8 alt2">9</div>
<div class="line number10 index9 alt1">10</div>
<div class="line number11 index10 alt2">11</div>
<div class="line number12 index11 alt1">12</div>
<div class="line number13 index12 alt2">13</div>
<div class="line number14 index13 alt1">14</div>
<div class="line number15 index14 alt2">15</div>
<div class="line number16 index15 alt1">16</div>
<div class="line number17 index16 alt2">17</div>
<div class="line number18 index17 alt1">18</div>
<div class="line number19 index18 alt2">19</div>
<div class="line number20 index19 alt1">20</div>
<div class="line number21 index20 alt2">21</div>
<div class="line number22 index21 alt1">22</div>
<div class="line number23 index22 alt2">23</div>
</td>
<td class="code">
<div class="container">
<div class="line number1 index0 alt2"><code class="py keyword">import</code> <code class="py plain">functools</code></div>
<div class="line number2 index1 alt1"><code class="py keyword">def</code> <code class="py plain">use_logging(arg):</code></div>
<div class="line number3 index2 alt2"><code class="py spaces"> </code><code class="py keyword">if</code> <code class="py functions">callable</code><code class="py plain">(arg):</code><code class="py comments">#判断参入的参数是否是函数,不带参数的装饰器调用这个分支</code></div>
<div class="line number4 index3 alt1"><code class="py spaces"> </code><code class="py decorator">@functools</code><code class="py plain">.wraps(arg)</code></div>
<div class="line number5 index4 alt2"><code class="py spaces"> </code><code class="py keyword">def</code> <code class="py plain">_deco(</code><code class="py keyword">*</code><code class="py plain">args,</code><code class="py keyword">*</code><code class="py keyword">*</code><code class="py plain">kwargs):</code></div>
<div class="line number6 index5 alt1"><code class="py spaces"> </code><code class="py functions">print</code><code class="py plain">(</code><code class="py string">"%s is running"</code> <code class="py keyword">%</code> <code class="py plain">arg.__name__)</code></div>
<div class="line number7 index6 alt2"><code class="py spaces"> </code><code class="py plain">arg(</code><code class="py keyword">*</code><code class="py plain">args,</code><code class="py keyword">*</code><code class="py keyword">*</code><code class="py plain">kwargs)</code></div>
<div class="line number8 index7 alt1"><code class="py spaces"> </code><code class="py keyword">return</code> <code class="py plain">_deco</code></div>
<div class="line number9 index8 alt2"><code class="py spaces"> </code><code class="py keyword">else</code><code class="py plain">:</code><code class="py comments">#带参数的装饰器调用这个分支</code></div>
<div class="line number10 index9 alt1"><code class="py spaces"> </code><code class="py keyword">def</code> <code class="py plain">_deco(func):</code></div>
<div class="line number11 index10 alt2"><code class="py spaces"> </code><code class="py decorator">@functools</code><code class="py plain">.wraps(func)</code></div>
<div class="line number12 index11 alt1"><code class="py spaces"> </code><code class="py keyword">def</code> <code class="py plain">__deco(</code><code class="py keyword">*</code><code class="py plain">args, </code><code class="py keyword">*</code><code class="py keyword">*</code><code class="py plain">kwargs):</code></div>
<div class="line number13 index12 alt2"><code class="py spaces"> </code><code class="py keyword">if</code> <code class="py plain">arg </code><code class="py keyword">=</code><code class="py keyword">=</code> <code class="py string">"warn"</code><code class="py plain">:</code></div>
<div class="line number14 index13 alt1"><code class="py spaces"> </code><code class="py functions">print</code> <code class="py string">"warn%s is running"</code> <code class="py keyword">%</code> <code class="py plain">func.__name__</code></div>
<div class="line number15 index14 alt2"><code class="py spaces"> </code><code class="py keyword">return</code> <code class="py plain">func(</code><code class="py keyword">*</code><code class="py plain">args, </code><code class="py keyword">*</code><code class="py keyword">*</code><code class="py plain">kwargs)</code></div>
<div class="line number16 index15 alt1"><code class="py spaces"> </code><code class="py keyword">return</code> <code class="py plain">__deco</code></div>
<div class="line number17 index16 alt2"><code class="py spaces"> </code><code class="py keyword">return</code> <code class="py plain">_deco</code></div>
<div class="line number18 index17 alt1"><code class="py decorator">@use_logging</code><code class="py plain">(</code><code class="py string">"warn"</code><code class="py plain">)</code></div>
<div class="line number19 index18 alt2"><code class="py comments"># @use_logging</code></div>
<div class="line number20 index19 alt1"><code class="py keyword">def</code> <code class="py plain">bar():</code></div>
<div class="line number21 index20 alt2"><code class="py spaces"> </code><code class="py functions">print</code><code class="py plain">(</code><code class="py string">'i am bar'</code><code class="py plain">)</code></div>
<div class="line number22 index21 alt1"><code class="py spaces"> </code><code class="py functions">print</code><code class="py plain">(bar.__name__)</code></div>
<div class="line number23 index22 alt2"><code class="py plain">bar()</code></div>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<p><strong>三、类装饰器</strong></p>
<p>使用类装饰器可以实现带参数装饰器的效果,但实现的更加优雅简洁,而且可以通过继承来灵活的扩展.</p>
<p>1、类装饰器</p>
<div class="jb51code">
<div>
<div id="highlighter_371240" class="syntaxhighlighterpy">
<div class="toolbar">?</div>
<table border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td class="gutter">
<div class="line number1 index0 alt2">1</div>
<div class="line number2 index1 alt1">2</div>
<div class="line number3 index2 alt2">3</div>
<div class="line number4 index3 alt1">4</div>
<div class="line number5 index4 alt2">5</div>
<div class="line number6 index5 alt1">6</div>
<div class="line number7 index6 alt2">7</div>
<div class="line number8 index7 alt1">8</div>
<div class="line number9 index8 alt2">9</div>
<div class="line number10 index9 alt1">10</div>
<div class="line number11 index10 alt2">11</div>
<div class="line number12 index11 alt1">12</div>
<div class="line number13 index12 alt2">13</div>
<div class="line number14 index13 alt1">14</div>
<div class="line number15 index14 alt2">15</div>
<div class="line number16 index15 alt1">16</div>
<div class="line number17 index16 alt2">17</div>
</td>
<td class="code">
<div class="container">
<div class="line number1 index0 alt2"><code class="py keyword">class</code> <code class="py plain">loging(</code><code class="py functions">object</code><code class="py plain">):</code></div>
<div class="line number2 index1 alt1"><code class="py spaces"> </code><code class="py keyword">def</code> <code class="py plain">__init__(</code><code class="py color1">self</code><code class="py plain">,level</code><code class="py keyword">=</code><code class="py string">"warn"</code><code class="py plain">):</code></div>
<div class="line number3 index2 alt2"><code class="py spaces"> </code><code class="py color1">self</code><code class="py plain">.level </code><code class="py keyword">=</code> <code class="py plain">level</code></div>
<div class="line number4 index3 alt1"><code class="py spaces"> </code><code class="py keyword">def</code> <code class="py plain">__call__(</code><code class="py color1">self</code><code class="py plain">,func):</code></div>
<div class="line number5 index4 alt2"><code class="py spaces"> </code><code class="py decorator">@functools</code><code class="py plain">.wraps(func)</code></div>
<div class="line number6 index5 alt1"><code class="py spaces"> </code><code class="py keyword">def</code> <code class="py plain">_deco(</code><code class="py keyword">*</code><code class="py plain">args, </code><code class="py keyword">*</code><code class="py keyword">*</code><code class="py plain">kwargs):</code></div>
<div class="line number7 index6 alt2"><code class="py spaces"> </code><code class="py keyword">if</code> <code class="py color1">self</code><code class="py plain">.level </code><code class="py keyword">=</code><code class="py keyword">=</code> <code class="py string">"warn"</code><code class="py plain">:</code></div>
<div class="line number8 index7 alt1"><code class="py spaces"> </code><code class="py color1">self</code><code class="py plain">.notify(func)</code></div>
<div class="line number9 index8 alt2"><code class="py spaces"> </code><code class="py keyword">return</code> <code class="py plain">func(</code><code class="py keyword">*</code><code class="py plain">args, </code><code class="py keyword">*</code><code class="py keyword">*</code><code class="py plain">kwargs)</code></div>
<div class="line number10 index9 alt1"><code class="py spaces"> </code><code class="py keyword">return</code> <code class="py plain">_deco</code></div>
<div class="line number11 index10 alt2"><code class="py spaces"> </code><code class="py keyword">def</code> <code class="py plain">notify(</code><code class="py color1">self</code><code class="py plain">,func):</code></div>
<div class="line number12 index11 alt1"><code class="py spaces"> </code><code class="py comments"># logit只打日志,不做别的</code></div>
<div class="line number13 index12 alt2"><code class="py spaces"> </code><code class="py functions">print</code> <code class="py string">"%s is running"</code> <code class="py keyword">%</code> <code class="py plain">func.__name__</code></div>
<div class="line number14 index13 alt1"><code class="py decorator">@loging</code><code class="py plain">(level</code><code class="py keyword">=</code><code class="py string">"warn"</code><code class="py plain">)</code><code class="py comments">#执行__call__方法</code></div>
<div class="line number15 index14 alt2"><code class="py keyword">def</code> <code class="py plain">bar(a,b):</code></div>
<div class="line number16 index15 alt1"><code class="py spaces"> </code><code class="py functions">print</code><code class="py plain">(</code><code class="py string">'i am bar:%s'</code><code class="py keyword">%</code><code class="py plain">(a</code><code class="py keyword">+</code><code class="py plain">b))</code></div>
<div class="line number17 index16 alt2"><code class="py plain">bar(</code><code class="py value">1</code><code class="py plain">,</code><code class="py value">3</code><code class="py plain">)</code></div>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<p>2、继承扩展类装饰器</p>
<div class="jb51code">
<div>
<div id="highlighter_715359" class="syntaxhighlighterpy">
<div class="toolbar">?</div>
<table border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td class="gutter">
<div class="line number1 index0 alt2">1</div>
<div class="line number2 index1 alt1">2</div>
<div class="line number3 index2 alt2">3</div>
<div class="line number4 index3 alt1">4</div>
<div class="line number5 index4 alt2">5</div>
<div class="line number6 index5 alt1">6</div>
<div class="line number7 index6 alt2">7</div>
<div class="line number8 index7 alt1">8</div>
<div class="line number9 index8 alt2">9</div>
<div class="line number10 index9 alt1">10</div>
<div class="line number11 index10 alt2">11</div>
<div class="line number12 index11 alt1">12</div>
<div class="line number13 index12 alt2">13</div>
<div class="line number14 index13 alt1">14</div>
<div class="line number15 index14 alt2">15</div>
</td>
<td class="code">
<div class="container">
<div class="line number1 index0 alt2"><code class="py keyword">class</code> <code class="py plain">email_loging(Loging):</code></div>
<div class="line number2 index1 alt1"><code class="py spaces"> </code><code class="py comments">'''</code></div>
<div class="line number3 index2 alt2"><code class="py spaces"> </code><code class="py comments">一个loging的实现版本,可以在函数调用时发送email给管理员</code></div>
<div class="line number4 index3 alt1"><code class="py spaces"> </code><code class="py comments">'''</code></div>
<div class="line number5 index4 alt2"><code class="py spaces"> </code><code class="py keyword">def</code> <code class="py plain">__init__(</code><code class="py color1">self</code><code class="py plain">, email</code><code class="py keyword">=</code><code class="py string">'admin@myproject.com'</code><code class="py plain">, </code><code class="py keyword">*</code><code class="py plain">args, </code><code class="py keyword">*</code><code class="py keyword">*</code><code class="py plain">kwargs):</code></div>
<div class="line number6 index5 alt1"><code class="py spaces"> </code><code class="py color1">self</code><code class="py plain">.email </code><code class="py keyword">=</code> <code class="py plain">email</code></div>
<div class="line number7 index6 alt2"><code class="py spaces"> </code><code class="py functions">super</code><code class="py plain">(email_loging, </code><code class="py color1">self</code><code class="py plain">).__init__(</code><code class="py keyword">*</code><code class="py plain">args, </code><code class="py keyword">*</code><code class="py keyword">*</code><code class="py plain">kwargs)</code></div>
<div class="line number8 index7 alt1"><code class="py spaces"> </code><code class="py keyword">def</code> <code class="py plain">notify(</code><code class="py color1">self</code><code class="py plain">,func):</code></div>
<div class="line number9 index8 alt2"><code class="py spaces"> </code><code class="py comments"># 发送一封email到self.email</code></div>
<div class="line number10 index9 alt1"><code class="py spaces"> </code><code class="py functions">print</code> <code class="py string">"%s is running"</code> <code class="py keyword">%</code> <code class="py plain">func.__name__</code></div>
<div class="line number11 index10 alt2"><code class="py spaces"> </code><code class="py functions">print</code> <code class="py string">"sending email to %s"</code> <code class="py keyword">%</code><code class="py color1">self</code><code class="py plain">.email</code></div>
<div class="line number12 index11 alt1"><code class="py decorator">@email_loging</code><code class="py plain">(level</code><code class="py keyword">=</code><code class="py string">"warn"</code><code class="py plain">)</code></div>
<div class="line number13 index12 alt2"><code class="py keyword">def</code> <code class="py plain">bar(a,b):</code></div>
<div class="line number14 index13 alt1"><code class="py spaces"> </code><code class="py functions">print</code><code class="py plain">(</code><code class="py string">'i am bar:%s'</code><code class="py keyword">%</code><code class="py plain">(a</code><code class="py keyword">+</code><code class="py plain">b))</code></div>
<div class="line number15 index14 alt2"><code class="py plain">bar(</code><code class="py value">1</code><code class="py plain">,</code><code class="py value">3</code><code class="py plain">)</code></div>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
<div id="MySignature" role="contentinfo">
arvin_feng<br><br>
来源:https://www.cnblogs.com/arvin-feng/p/11108799.html
頁:
[1]