博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
对Python装饰器的个人理解方法
阅读量:6247 次
发布时间:2019-06-22

本文共 2554 字,大约阅读时间需要 8 分钟。

0.说明

         

        在自己好好总结并对Python装饰器的执行过程进行分解之前,对于装饰器虽然理解它的基本工作方式,但对于存在复杂参数的装饰器(装饰器和函数本身都有参数),总是会感到很模糊,即使这会弄懂了,下一次也很快忘记,其实本质上还是没有多花时间去搞懂其中的细节问题。

        虽然网络上已经有很多这样的文章,但显然都是别人的思想,因此自己总是记不牢,所以花点时间自己好好整理一下。

        最近在对《Python核心编程》做总结,收获了不少,下面分享一下我自己对于Python装饰器的理解,后面还提供了一个较为复杂的Python装饰器的执行过程的分解,可以参考一下。


1.Python装饰器的出现

         在没有装饰器之前,如果要在类中定义一个静态方法,需要使用下面的方法:

1
2
3
class 
MyClass(
object
):
    
def 
staticFoo():
        
staticFoo 
= 
staticmethod
(staticFoo)

        即要在该静态方法中加入类似staticmethod()内建函数将该方法转换为静态方法,这显然非常麻烦,而有了装饰器之后,就可以写成下面这样:

1
2
3
4
class 
MyClass(
object
):
    
@
staticmethod
    
def 
staticFoo():
        
pass

        这样就简洁很多了。


2.Python装饰器类型与理解

(1)无参数装饰器    

  • 一个装饰器

        下面的情况:

1
2
3
@f
def 
foo():
    
pass

        其实就相当于:

1
2
3
def 
foo():
    
pass
foo 
= 
g(foo)
  • 多个装饰器

        下面的情况:

1
2
3
4
@g
@f
def 
foo():
    
pass

        就相当于:

1
2
3
def 
foo():
    
pass
foo 
= 
g(f(foo))

(2)含参数装饰器

  • 带有参数的一个装饰器

        下面的情况:

1
2
3
@decomaker
(deco_args)
def 
foo():
    
pass

        就相当于:

1
2
3
def 
foo():
    
pass
foo 
= 
decomaker(deco_args)(foo)

        用这样的思想去理解就非常好理解了:decomaker()用deco_args做了些事并返回函数对象,而该函数对象正是以foo作为其参数的装饰器

        下面多个装饰器的例子也是按这样的思想去理解。

  • 带有参数的多个装饰器

        下面的情况:

1
2
3
4
@deco1
(deco_arg)
@deco2
()
def 
foo():
    
pass

        就相当于:

1
2
3
def 
foo():
    
pass
foo 
= 
deco1(deco_arg)(deco2(foo))


3.Python装饰器执行过程的手动分解

        OK,有了上面的理论基础,理解下面一个较为复杂的装饰器就很容易了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from 
functools 
import 
wraps
 
def 
log(text):
    
def 
decorator(func):
        
@wraps(func)                    
#it works like:wraper.__name__ = func.__name__
        
def 
wrapper(
*
args, 
*
*
kwargs):
            
print 
'%s %s():' 
% 
(text, func.__name__)
            
return 
func(
*
args, 
*
*
kwargs)
        
return 
wrapper
    
return 
decorator
 
 
@log
(
'Hello'
)
def 
now(area):
    
print 
area, 
'2016-01-23'
     
 
now(
'Beijing'
)
print 
'The name of function now() is:'
, now.__name__

        执行如下:

1
2
3
4
/
usr
/
bin
/
python2.
7 
/
home
/
xpleaf
/
PycharmProjects
/
decorator_test
/
dec10.py
Hello now():
Beijing 
2016
-
01
-
23
The name of function now() 
is
: now

对于该程序的执行过程,可以分析如下:

1.先执行log('Hello')函数,此时返回了一个新的函数,只不过其中的text变量被替换为'Hello',所以用来装饰now函数的新的装饰器如下:

1
2
3
4
5
6
def 
decorator(func):
    
@wraps(func)                    
#it works like:wraper.__name__ = func.__name__
    
def 
wrapper(
*
args, 
*
*
kwargs):
        
print 
'%s %s():' 
% 
(
'Hello'
, func.__name__)
        
return 
func(
*
args, 
*
*
kwargs)
    
return 
wrapper

2.所以此时的now函数,就相当于:

1
now 
= 
decorator(now)

3.即now就相当于:

1
2
3
4
def 
now(
*
args, 
*
*
kwargs):
    
print 
'%s %s():' 
% 
(
'Hello'
, old_now.__name__)
    
return 
old_now(
*
args, 
*
*
kwargs)
# 现在的函数名称变为了now而不是wrapper,是因为使用了wraps装饰器

   所以,输出的结果也就非常好理解了。

        关于wraps,它也是一个装饰器,使用它的作用是,被我们用自定义装饰器修改后的函数,它的函数名称,即func.__name__跟原来是一样的,而它的工作原理正如上面所提及的,即:

1
wraper.__name__ 
= 
func.__name__

        也就是说,使用wraps可以不改变原来函数的属性,当然,上面只是简单说明了一下其工作原理,详细的可以参考wraps的源代码。

        在GitHub上给出了10个理解装饰器的例子,可以参考一下:

转载地址:http://admia.baihongyu.com/

你可能感兴趣的文章
Django之restframework
查看>>
P3924 康娜的线段树
查看>>
Vue的安装和语法
查看>>
验证表单必须为数字并且只保留小数点后2位
查看>>
2-sat基础题 uvalive 3211
查看>>
Elasticsearch5.2.0部署过程的坑
查看>>
go build 不同系统下的可执行文件
查看>>
浏览器版本信息判断整理
查看>>
【我的Android进阶之旅】解决Android Studio 运行gradle命令时报错: 错误: 编码GBK的不可映射字符...
查看>>
windows 下解决 Time_Wait 和 CLOSE_WAIT 方法
查看>>
SOUI Editor使用教程
查看>>
PHP字符串的替换(preg_replace)
查看>>
责任链模式的具体应用
查看>>
Nginx安装
查看>>
Aix下查看内存命令
查看>>
[Android]JsonObject解析
查看>>
最好用的软件快速开发平台-全部源码-3800/套
查看>>
移动端fixed后 横竖屏切换时上部或下部出现空隙问题
查看>>
Django ORM 操作 必知必会13条 单表查询
查看>>
selenium 安装与 chromedriver安装
查看>>