面向切片编程AOP之装饰器、迭代器、生成器
一、装饰器
装饰器的本质是闭包
闭包:(通常函数在调用完之后,函数内部定义的变量也销毁了)
作用:闭包可以保存外部函数内的变量,不会随着外部函数调用完而销毁
现实意义:闭包可以提高代码的复用性,不需要再手动定义额外的功能函数
注意点:由于闭包引用外部函数的变量,则外部函数的变量没有及时的释放,消耗内存
函数的嵌套、内部函数使用外部函数的变量、并且外部函数返回内部函数
def func_out(num1):
#定义一个内部函数
def func_inner(num2):
#本意我们是想要修改我们的外部变量Num1的值,但实际上是在我们的内部函数中重新定义了一个据不变量
#告诉解释器,此处用的是外部变量num1
nonlocal num1
#并且重新定义外部变量的值
num1 = 10
result = num1+num2
print("结果是:",result)
return func_inner
#创建闭包实例
#外层函数返回的是我们的内层函数
#所以执行闭包的时候传递进去的值是给了我们的内层函数
f = func_out(1)
#执行闭包。
#如果我们的内层函数存在返回值。则这里的闭包函数需要一个接收值
f(3)
f(4)
注意:
如果需要修改我们的外部函数的值,需要用到关键字nonlocal,并且进行重新的定义
装饰器:装饰器的本质就是一个闭包函数
功能特点:
-
不修改已有函数的源代码
-
不修改已有函数的调用方式
-
给已有函数增加额外的功能
实例:
def check(fn):
print("装饰器函数执行了")
def inner(num1,num2):#携带参数
print("评论前请先登录。。。")
fn(num1,num2)
return inner
# 装饰器的执行时间是加载模块时立即执行
# 等价于comment = check(comment)
@check
def comment(a,b):
print("发表评论")
comment(1,2)
#携带不定长参数:*args,**kwargs
运行结果:
[装饰器函数执行了] 外层装饰器函数
[评论前请先登录。。。] 内层装饰器函数
[发表评论] 被装饰函数
多个装饰器的使用
def make_div(func):
"""对被装饰的函数的返回值 div标签"""
def inner():
return "<div>" + func() + "</div>"
return inner
def make_p(func):
"""对被装饰的函数的返回值 p标签"""
def inner():
return "<p>" + func() + "</p>"
return inner
# 装饰过程: 1 content = make_p(content) 2 content = make_div(content)
# content = make_div(make_p(content))
@make_div
@make_p
def content():
return "人生苦短"
result = content()
print(result)
#运行结果:
<div><p>人生苦短</p></div>
#多个装饰器可以对函数进行多个功能的装饰,装饰顺序是由内到外的进行装饰
总结:多个装饰器的装饰过程是: 离函数最近的装饰器先装饰,然后外面的装饰器再进行装饰,由内到外的装饰过程
带有参数的装饰器:
def logging(flag):
#外部包装
#内部装饰器
def decorator(fn):
def inner(num1, num2):
#外部包装传递的参数进行判断
if flag == "+":
print("--正在努力加法计算")
elif flag == "-":
print("--正在努力减法计算")
result = fn(num1, num2)
return result
return inner
# 返回装饰器
return decorator
# 使用装饰器装饰函数
@logging("+")
def add(a, b):
result = a + b
return result
@logging("-")
def sub(a, b):
result = a - b
return result
result = add(1, 2)
print(result)
result = sub(1, 2)
print(result)
运行结果:
--正在努力加法计算
3
--正在努力减法计算
-1
总结:
使用带参数的装饰器,其实是在装饰器的外面又包裹了一个函数,使该函数接收参数,返回装饰器,因为@符号需要配合装饰器实例使用
类装饰器:
就是通过定义一个类来装饰函数
class Check(object):
def __init__(self,fn):
#初始化操作在此完成
self.__fn = fn
#实现__call__方法,表示对象是一个可调用对象,可以像调用函数一样进行调用
def __call__(self, *args, **kwargs):
#添加装饰功能
print("请先登录")
self.__fn()
@Check
def comment():
print("发表评论")
comment()
运行结果:
请先登录
发表评论
代码说明:
-
@Check 等价于 comment = Check(comment), 所以需要提供一个init方法,并多增加一个fn参数。
-
要想类的实例对象能够像函数一样调用,需要在类里面使用call方法,把类的实例变成可调用对象(callable),也就是说可以像调用函数一样进行调用。
-
在call方法里进行对fn函数的装饰,可以添加额外的功能
总结:
1、想要让类的实例对象能够像函数一样进行调度,需要在类里面使用call方法,把类的实例变成可调用对象(callable)
2、类装饰器装饰函数功能在call方法里面进行添加
二、迭代器
1、通过iter()方法获得list的迭代对象,然后就可以通过next()方法来访问list中的元素了。当容器中没有可访问的元素后,next()方法将会抛出一个StopIteration异常终止迭代器。字符串,列表元组对象都可用于创建迭代器:
2、不过迭代器是有先知的,例如
-
不能回到开始
-
也无法复制一个迭代器
-
因此要再次进行迭代只能重新生成一个新的迭代对象
3、iter()和next()方法,这俩个方法是迭代器最基本的方法
一个用来获取迭代对象
一个用来获取容器中的下一个元素
#iter方法和next方法的应用
list1 = [12,56,78,49,67,87]
it = iter(list1)
print(type(it))
#第一种方法
print(it.__next__())
print(it.__next__())
print(it.__next__())
print(it.__next__())
print(it.__next__())
print(it.__next__())
print(it.__next__())
#访问的元素超出list1时抛出StopIteration异常
#第二种方法
# print(next(it))
# print(next(it))
# print(next(it))
# print(next(it))
# print(next(it))
# print(next(it))
运行结果:
<class 'list_iterator'>
12
56
78
49
67
87
Traceback (most recent call last):
print(it.__next__())
StopIteration
自定义迭代器:
class MyIterration(object):
def __init__(self, n):
self.idx = 0
self.n = n
def __iter__(self):
return self
def __next__(self):
if self.idx < self.n:
val = self.idx
self.idx += 1
return val
else:
raise StopIteration()
ite = MyIterration(3)
print(next(ite))
print(next(ite))
print(next(ite))
# print(next(ite))
理解后可以尝试写一下列表,元组,字典的迭代器,其实都是差不多的
生成器
是一种特殊的迭代器
如果列表的元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间
在python中,这样一边循环一边计算的机制,称之为生成器
# 生成式就是将列表推导式的[]换成()就可以了
g = (x + x for x in range(10))
print(g)
print(next(g))
print(next(g))
print(next(g))
for n in g:
print(n)
# 示例代码
# 生成器函数的使用==斐波那契数列
def fib(max):
n, a, b = 0, 0, 1
while n < max:
yield b
a, b = b, a + b
n = n + 1
return 'done'
a = fib(10)
print(fib(10))
print(next(a))
print(next(a))
print(next(a))
print(next(a))
print(next(a))
学习笔记整理(1)