您的位置:首页 > 编程语言 > Python开发

python修炼——闭包、装饰器!

2018-09-04 18:53 197 查看

python 中的闭包和装饰器初接触,下面是一些概念和自己的理解。

闭包

实质就是函数的嵌套,内层函数往往会用到外层函数的数据

作用:

可以实现函数的功能,并且可以保存数据

相对于对象来说实现同样的功能(方法、保存数据)更节约内存

闭:把数据封闭在这个函数里面,

定义闭包:

创建一个闭包必须满足以下几点:

  • 必须有一个内嵌函数
  • 内嵌函数必须引用外部函数中的变量
  • 外部函数的返回值必须是内嵌函数
def outer(name):
def inner(age):
print("嵌套函数")
print("name:", name, "age:", age)
return inner

demo = outer("goudan")
demo(22)

# 执行结果
嵌套函数
name: goudan age: 22

"""
这里调用 outer 的时候就产生了一个闭包 —— inner, 并且该闭包持有自由变量—— name,
因此这也意味着,当函数 func 的生命周期结束之后,name 这个变量依然存在,
因为它被闭包引用了,所以不会被回收。
"""

闭包函数的调用流程

调用闭包的外层函数,返回闭包中的内层函数的引用

调用这个闭包函数的返回值,其实是在调用闭包里的内层函数

闭包和对象的区别:

闭包和对象都可以存储变量和方法

对象的系统开销大,闭包的系统开销小

对象是面向对象编程的思维模式

闭包是面向过程编程的思维模式,函数式编程

思考:函数、匿名函数、闭包、对象,当做实参时,有什么区别?

  1. 匿名函数能够完成基本的简单功能。。。传递的是这个函数的引用,只有功能
  2. 普通函数能够完成较为复杂的功能。。。传递的是这个函数的用意,只有功能
  3. 闭包能够完成较为复杂的功能。。。传递的是这个闭包中的函数以及数据,因此传递是功能+数据
  4. 对象能够完成最为复杂的功能。。传递的是很多数据和很多功能,因此传递的是功能+数据

装饰器

一、函数装饰器

装饰器的功能是将被装饰的函数当作参数传递给与装饰器对应的函数(名称相同的函数),并返回包装后的被装饰的函数

无参数的装饰器

def a(c):
def b():
print("bbb")
c()
return b

@a  # 相当于   d = a(d)
def d():
print("ddd")

d()

"""
1.python 解释器发现 @a ,就去调用与其相对应的函数(a()函数);
2.a 函数在调用前要传入一个参数,传入的就是 @a 下面修饰的函数的引用,也就是 d;
3. a 函数执行,d 函数的引用传参进来给 c,c 就指向了 d,然后碰见 b 函数,会定义,不执行;
4.此时返回 b 函数的引用给 d,d 函数相当于重写被定义,指向了 b;
5.调用此时的 d 函数,相当于开始执行 b 函数,先执行 b 函数中的代码,然后碰见了 c 函数调用;
6.c 函数指向了原来的 d 函数,开始执行原d 函数中的代码,结束运行

"""

有参数的装饰器

def set_func(func):
def call_func(a):
print("---这是权限验证1----")
print("---这是权限验证2----")
func(a)
return call_func

@set_func  # 相当于 test1 = set_func(test1)
def test1(num):
print("-----test1----%d" % num)

test1(100)
test1(200)

无返回值的装饰器

def set_func(func):
def call_func(a):
print("---这是权限验证1----")
print("---这是权限验证2----")
func(a)
return call_func

@set_func  # 相当于 test1 = set_func(test1)
def test1(num):
print("-----test1----%d" % num)

test1(100)
test1(200)

有返回值的装饰器

def set_func(func):
print("---开始进行装饰")
def call_func(*args, **kwargs):  # 可以接收多个参数,也可以不接收
print("---这是权限验证1----")
print("---这是权限验证2----")
# func(args, kwargs)  # 不行,相当于传递了2个参数 :1个元组,1个字典
return func(*args, **kwargs)  # 拆包, 接收到多值参数需要进行拆包才能进行传参
return call_func

@set_func  # 相当于 test1 = set_func(test1)
def test1(num, *args, **kwargs):
print("-----test1----%d" % num)
print("-----test1----" , args)
print("-----test1----" , kwargs)
return "ok"

@set_func
def test2():
pass

ret = test1(100)
print(ret)

ret = test2()
print(ret)

通用的装饰器

不管是有无参数,有无返回值用通用的装饰器都行

def set_func(func):
def call_func(*args, **kwargs):
print("---添加的功能----")
retun func(*args, **kwargs)
return call_func

一个装饰器装饰多个函数

一个装饰器可以装饰多个函数 ,

在调用前就已经开始装饰了

装饰的时候并不会互相影响

def set_func(func):
def call_func(a):
print("---这是权限验证1----")
print("---这是权限验证2----")
func(a)
return call_func

@set_func  # 相当于 test1 = set_func(test1)
def test1(num):
print("-----test1----%d" % num)

@set_func  # 相当于 test2 = set_func(test2)
def test2(num):
print("-----test2----%d" % num)

test1(100)
test2(200)

多个装饰器装饰一个函数

离函数近的先装饰

装饰器中内层函数的执行顺序,按照函数上所写的装饰器的顺序调用

def set_func_1(func):
def call_func():
# "<h1>haha</h1>"
return "<h1>" + func() + "</h1>"
return call_func

def set_func_2(func):
def call_func():
return "<td>" + func() + "</td>"
return call_func

@set_func_1
@set_func_2
def get_str():
return "haha"

print(get_str())

# 执行结果
<h1><td>haha</td></h1>

"""
1.代码从上往下执行,碰到第一个装饰器 set_func_1 的时候,因为下面不是函数,所以会略过,

2.碰见第二个装饰器 set_func_2,下面是函数,所以开始装饰,相当于执行了一句
get_str = set_func_2(get_str), 此时 get_str 就指向了 set_func_2 装饰器中的 call_func 这个函数,

3.此时第一个装饰器 set_func_1 下面就是一个函数,所以开始装饰,相当于执行了一句
get_str = set_func_1(get_str), 不过此时传递过去的引用是 set_func_2 中的嵌套函数的引用,
此时 get_str 就指向了 set_func_1 中的 call_func 这个函数,

4.调用此时的 get_str 函数, 先执行 set_func_1 中的 call_func, 执行中碰到 func() 函数,
set_func_1 中的 func() 这个函数此时的指向是 set_func_2 装饰器中的 call_func 这个函数,
在执行中碰到 set_func_2 中的 func() 函数,set_func_2 中的 func() 指向的是原先的 get_str() 函数,

5. 执行会返回 "haha",返回回到 set_func_2 中进行组合,
返回 <td>haha</td>,再回到set_func_1 中进行组合,得到最终结果 <h1><td>haha</td></h1>
"""

二、类装饰器

类装饰器现在只需要有个了解,后面会再详细介绍

class Test(object):
def __init__(self, func):
self.func = func

def __call__(self, *args, **kwargs):
print("----Test---")
return self.func()  # 调用

@Test  # 相当于  test = Test(test)
def test():
print("哈哈哈")

print(test())
阅读更多
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: