Python基础知识整理 12-闭包、装饰器

1 闭包

  • python中的函数有一些特点: 函数内可以定义函数; 函数可以作为参数被传递; 函数可以作为另一个函数的返回值
  • 闭包函数的本质其实是一个嵌套函数
  • 外层函数为内层函数提供了一个运行环境, 内层函数被当成返回值返回给外层函数
  • 从python语法上, 可以通过函数的__closure__方法来判断一个函数是否为闭包函数

# -*- coding: utf-8 -*-


# 定义一个函数
def func(number):
    # 在函数内部再定义一个函数,并且这个函数用到了外边函数的变量,那么将这个函数以及用到的一些变量称之为闭包
    def test_in(number_in):
        print("in test_in 函数, number_in is %d" % number_in)
        return number + number_in

    # 其实这里返回的就是闭包的结果
    return test_in


# 给test函数赋值,这个20就是给参数number
ret = func(20)

# 注意这里的100其实给参数number_in
print(ret(100))

# 注 意这里的200其实给参数number_in
print(ret(200))

"""
in test_in 函数, number_in is 100
120
in test_in 函数, number_in is 200
220
"""
 

2 装饰器

装饰器是用来装饰函数和类

装饰器在不破坏原有函数结构的情况下, 可以进行功能扩展

使用装饰器, 可以增加代码的可读性, 让代码层次结构变得更加清晰

例1:无参数的函数

from time import ctime, sleep

def timefun(func):

def wrapped_func():

print("%s called at %s" % (func.__name__, ctime()))

func()

return wrapped_func

@timefun

def foo():

print("I am foo")

foo()

sleep(2)

foo()

上面代码理解装饰器执行行为可理解成

foo = timefun(foo)

# foo先作为参数赋值给func后,foo接收指向timefun返回的wrapped_func

foo()

# 调用foo(),即等价调用wrapped_func()

# 内部函数wrapped_func被引用,所以外部函数的func变量(自由变量)并没有释放

# func里保存的是原foo函数对象

例2:被装饰的函数有参数

from time import ctime, sleep

def timefun(func):

def wrapped_func(a, b):

print("%s called at %s" % (func.__name__, ctime()))

print(a, b)

func(a, b)

return wrapped_func

@timefun

def foo(a, b):

print(a+b)

foo(3,5)

sleep(2)

foo(2,4)

例3:被装饰的函数有不定长参数

from time import ctime, sleep

def timefun(func):

def wrapped_func(*args, **kwargs):

print("%s called at %s"%(func.__name__, ctime()))

func(*args, **kwargs)

return wrapped_func

@timefun

def foo(a, b, c):

print(a+b+c)

foo(3,5,7)

sleep(2)

foo(2,4,9)

例4:装饰器中的return

from time import ctime, sleep

def timefun(func):

def wrapped_func():

print("%s called at %s" % (func.__name__, ctime()))

func()

return wrapped_func

@timefun

def foo():

print("I am foo")

@timefun

def getInfo():

return '----hahah---'

foo()

sleep(2)

foo()

print(getInfo())

执行结果:

foo called at Fri Nov 4 21:55:35 2016

I am foo

foo called at Fri Nov 4 21:55:37 2016

I am foo

getInfo called at Fri Nov 4 21:55:37 2016

None

如果修改装饰器为return func(),则运行结果:

foo called at Fri Nov 4 21:55:57 2016

I am foo

foo called at Fri Nov 4 21:55:59 2016

I am foo

getInfo called at Fri Nov 4 21:55:59 2016

----hahah---

总结:

一般情况下为了让装饰器更通用,可以有return

例5:装饰器带参数,在原有装饰器的基础上,设置外部变量

#decorator2.py

from time import ctime, sleep

def timefun_arg(pre="hello"):

def timefun(func):

def wrapped_func():

print("%s called at %s %s" % (func.__name__, ctime(), pre))

return func()

return wrapped_func

return timefun

# 下面的装饰过程

# 1. 调用timefun_arg("itcast")

# 2. 将步骤1得到的返回值,即time_fun返回, 然后time_fun(foo)

# 3. 将time_fun(foo)的结果返回,即wrapped_func

# 4. 让foo = wrapped_fun,即foo现在指向wrapped_func

@timefun_arg("itcast")

def foo():

print("I am foo")

@timefun_arg("python")

def too():

print("I am too")

foo()

sleep(2)

foo()

too()

sleep(2)

too()

可以理解为

foo()==timefun_arg("itcast")(foo)()

例6:类装饰器(扩展,非重点)

装饰器函数其实是这样一个接口约束,它必须接受一个callable对象作为参数,然后返回一个callable对象。在Python中一般callable对象都是函数,但也有例外。只要某个对象重写了 __call__() 方法,那么这个对象就是callable的。

class Test():

def __call__(self):

print('call me!')

t = Test()

t() # call me

类装饰器demo

class Test(object):

def __init__(self, func):

print("---初始化---")

print("func name is %s"%func.__name__)

self.__func = func

def __call__(self):

print("---装饰器中的功能---")

self.__func()

#说明:

#1. 当用Test来装作装饰器对test函数进行装饰的时候,首先会创建Test的实例对象

# 并且会把test这个函数名当做参数传递到__init__方法中

# 即在__init__方法中的属性__func指向了test指向的函数

#

#2. test指向了用Test创建出来的实例对象

#

#3. 当在使用test()进行调用时,就相当于让这个对象(),因此会调用这个对象的__call__方法

#

#4. 为了能够在__call__方法中调用原来test指向的函数体,所以在__init__方法中就需要一个实例属性来保存这个函数体的引用

# 所以才有了self.__func = func这句代码,从而在调用__call__方法中能够调用到test之前的函数体

@Test

def test():

print("----test---")

test()

showpy()#如果把这句话注释,重新运行程序,依然会看到"--初始化--"

运行结果如下:

---初始化---

func name is test

---装饰器中的功能---

----test---

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

轨迹|

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值