【Python】浅析闭包与装饰器

【Python】浅析闭包与装饰器

前言

在此之前,需要认清以下几点:
1,变量可以指向一个函数。

>>> f = abs  #变量f指向abs
>>> f
<built-in function abs>
>>> f(-1)
1

2,函数名是指向函数的变量。

>>> abs = len  #abs 指向函数len。
>>> abs
<built-in function len>
>>> abs(-2)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: object of type 'int' has no len()
>>> abs('length')
6

3,函数也是对象;

>>> def funt():
...    pass
...
>>> funt.__class__
<class 'function'>
>>> issubclass(funt.__class__,object)
True

4,一个函数可以作为另一个函数的参数

>>> def add(x,y,f):
...    return f(x) + f(y)
...
>>> add(-9,2,abs)
11

闭包

闭包的定义有很多,但是不管怎么样定义,有几个点是不会变的!
1,函数嵌套,也就是函数内部再定义一个新函数,可以说是外函数和内函数。
2,内函数使用到外函数定义的局部变量
3,外函数返回内函数的引用,根据前言所说可以理解为内函数名,
举个栗子:

 # outer是外部函数 x外函数的临时变量
def outer():
    x = 1
    # inner是内函数
    def inner():
    #在内函数中 用到了外函数的临时变量
        print(x)
    # 外函数的返回值是内函数的引用
    return inner
#
f = outer()
f()    # 1

1,返回引用。
对于闭包,在外函数outer中 最后return inner,我们在调用外函数 f = outer() 的时候,outer返回了inner,inner是一个函数的引用,根据前言所说,可以理解为变量,这个引用被存入了变量f中,相当于 f = inner()。所以接下来我们再进行f() 的时候,相当于运行了inner函数。一个函数,如果函数名后紧跟一对括号,相当于现在我就要调用这个函数,如果不跟括号,相当于只是一个函数的名字,里面存了函数所在位置的引用。
2,内函数使用到外函数定义的局部变量。
一般情况下,一个函数结束的时候,会把自己的临时变量都释放还给内存,之后变量都不存在了。但是闭包是一个特别的情况。外部函数发现,自己的临时变量会在将来的内部函数中用到,自己在结束的时候,返回内函数的同时,会把外函数的临时变量送给内函数绑定在一起。所以外函数已经结束了,调用内函数的时候仍然能够使用外函数的临时变量。

装饰器

闭包的一种应用就是装饰器,将一个函数作为外函数的参数传入,通过内函数对传入的函数进行修改装饰,再将内函数返回,装饰器不能影响原函数的功能,装饰器是独立出来的函数。谁调用它,谁就可以使用它的功能。

def decorated(func):
    def logger(x,y):
        print('x+y')
        return func(x,y)
    return logger

def add(x,y):
    return x+y
add = decorated(add)   # 对add进行装饰,改变其原有功能
print(add(-2,3))

简化代码,使用 @ 标识符将装饰器应用到函数

def decorated(func):
    def logger(x,y):
        print('x+y')
        return func(x,y)
    return logger
#只需要在函数的定义前加上@和装饰器的名称。
@decorated
def add(x,y):
    return x+y

# add = decorated(add)
print(add(-2,3))

通用的装饰器

def decorated(func):
    def logger(*arges,**kwarges):
        print("arges={},kwarges={}".format(arges,kwarges))    
        return func(*arges,**kwarges)
    return logger

@decorated
def add(x,y):
    return x+y
    
print(add(x=9,y=3))
print(add(9,3))
print(add(9,y=3))

#输出结果:
arges=(),kwarges={'x': 9, 'y': 3}
12
arges=(9, 3),kwarges={}
12
arges=(9,),kwarges={'y': 3}
12

现在的add可以接收不同类型的参数。

收集参数

def print_params(*params):
 print(params) 
print_params('Testing')      #('Testing',)   返回一个元祖

参数前面的一个星号将提供的所有值都放在一个元组中,也就是将这些值收集起来。但是一个星号不能收集关键字参数,

def print_params(*params):
    print(params) 
print_params(key='Testing')  
#TypeError: print_params() got an unexpected keyword argument 'key'

要收集关键字参数,可使用两个星号,这样得到的是一个字典而不是元组。

def print_params(**params):
    print(params) 
print_params(key='Testing')
#{'key': 'Testing'}     返回一个字典

再举个栗子

def print_params(x, y, z=4, *pospar, **keypar):
    print(x, y, z)
    print(pospar)
    print(keypar) 
print_params(1, 2, 3, 5, 6, 7, foo=1, bar=2) 

#输出结果
1 2 3
(5, 6, 7)
{'foo': 1, 'bar': 2}

综上觉得Python真的是一门很神奇的语言,有好多神奇和高效的特性,怪不得刚出现时,大家都说Python简单,但是要理解这些特性背后的东西,又需要琢磨一阵子。

参考
http://python.jobbole.com/81683/
《Python 基础教程》(第3版)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值