python装饰器

本文详细介绍了Python中闭包和装饰器的概念,通过示例展示了如何使用装饰器为函数添加额外功能,并讨论了装饰器的应用场景及注意事项。文章还提供了一个简单的日志装饰器实现,以及对装饰器与静态方法、类方法的区别说明。

了解装饰器,要先了解闭包。

 

1,闭包(closure)

闭包是Python所支持的一种特性,它让在非global scope定义的函数可以引用其外围空间中的变量,这些外围空间中被引用的变量叫做这个函数的环境变量。环境变量和这个非全局函数一起构成了闭包。

复制代码
 1 def outer(x):
 2     y = [1,2,3]
 3     def inner():
 4         print x
 5         print y
 6     return inner
 7 
 8 x = 5    #这个x没有被引用
 9 f = outer(2)
10 f()
11 print f.__closure__   #函数属性__closure__存储了函数的环境变量
复制代码

x和y都是属于函数outer命名空间的,在inner中被引用,当outer函数退出后,outer的命名空间不存在了,但是inner依然维护了其定义时候对其外部变量x,y的连接。

程序输出:

  2
  [1, 2, 3]
  (<cell at 0x7f672a5b98d8: int object at 0x23a3c50>, <cell at 0x7f672a5b9910: list object at 0x7f672a5a03f8>)

 

 

2,装饰器(Decorator)

装饰器是一个可调用对象(a callable),在Python中,函数是对象,当然也是可调用的,所以装饰器可以是一个函数,我们称其为函数装饰器。

这个可调用对象以一个函数作为参数,并且返回另一个函数(来替换参数那个函数)。

比如:

1 def entrance(func):
2     def inner():
3         print "inside function :", func.__name__
4         func()
5     return inner

entrance是一个装饰器,它是一个函数,它可以接收一个函数func作为参数,返回了另一个函数inner。

 

那为什么叫装饰器了,在返回函数inner()的内部,调用了func(),而且还作了额外的操作,相当于“装饰”了函数func。

 

那如何使用装饰器?

复制代码
1 def fun1():
2     pass
3 fun1 = entrance(fun1)
4 
5 def fun2():
6     pass
7 fun2 = entrance(fun2)
复制代码

fun1,fun2的名字都没有变,但是通过调用函数装饰器entrance(),它们已经指向了另一个函数inner(),“装饰了”自己。

 

@操作符

Python提供的@符号,实质上就是上面做的,对一个函数名进行从新赋值,是语法上的技巧。所以上面的代码等价于

复制代码
1 @entrance
2 def fun1():
3     pass
4 
5 @entrance
6 def fun2():
7     pass
复制代码

 

装饰器的用途?

从这个刻意构造的很简单的例子,可以看出装饰器的意义,如果一个函数需要一个功能,如果这个功能可以被使用在很多函数上,或是函数并不是自己实现,那可以写个装饰器来实现这些功能。

上面的装饰器entrance,装饰一个函数后,函数被调用时会打印出这个函数的名字。

 

但是有一个问题,这个装饰器从功能上看,是要应该可以用来装饰任何函数,但是如果我们用它来装饰了一个带参数的函数

1 @entrance
2 def fun3(x):
3     pass

只要不调用fun3,这三行代码是不会让Python解释器报错的,因为我们已经知道,它等价于:

def fun3(x):
    pass
fun3 = entrance(fun3)

我们定义了一个带参的函数fun3,然后把fun3指向了另一个函数inner(),当然不会有什么错。

 

但是,当我们使用fun3时,我们肯定会按照它定义时的样子去使用它,给它传入一个参数。

>>>fun3(1)

这里就会出错了,看看解释器怎么报错的

Traceback (most recent call last):
File "decorator.py", line 23, in <module>
fun3(1)
TypeError: inner() takes no arguments (1 given)

当然我们已经很容易知到为什么会这样报错了,fun3已经不是指向它定义时那个函数了,它现在指向了"inner()",而inner是没有参数的,当然会出错。

 

那怎么解决呢?

 

修改一下inner()的定义,让它可以就收任意个参数就可以了   【注:参见Python函数一文】

1 def entrance(func):
2     def inner(*args, **kvargs):
3         print "inside function : ", func.__name__
4         func(*args, **kvargs)
5     return inner

现在,给inner传任意个参数都不会出错了,也就是entrance可以被用来装饰任何一个函数了。

 

 3,写个装饰器logger

一个函数被调用时,在日志里记录其名称和被调用的实际参数

复制代码
1 def logger(func):
2     def inner(*args, **kvargs):
3         print  func.__name__, 'called, arguments: ', args, kvargs
4         func(*args, **kvargs)
5     return inner
6         
复制代码

 

 python中实现静态方法和类方法都是依赖于python的修饰器来实现的。

class MyClass: 

    def  method(self): 

           print("method") 

    @staticmethod 

    def  staticMethod()

            print("static method") 

     @classmethod 

     def classMethod(cls)

           print("class method") 

 

大家注意到普通的对象方法、类方法和静态方法的去别了吗?

对象方法有self参数,类方法有cls参数,静态方法是不需要这些附加参数的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值