目录
4.迭代器(iterator)与可迭代(iterable)的区别
通过for循环遍历对象的每一个元素过程。
是一种可以遍历的对象,可以作用于next()函数,迭代器对象从第一个元素开始向后进行访问,直至最后一个元素,只能向后遍历不能向前回溯,与列表最大的区别就是列表遍历方向任意
- list1 = [1, 2, 3, 4, 5, 6]
- lt = iter(list1) # 创建迭代器对象lt
- for i in lt:
- print(i, end=' ')
-
- 结果:
- 1 2 3 4 5 6
由于序列或集合内的元素个数非常巨大,如果全部生成制造在一次性装入内存会对计算机造成非常大的存储压力,如果元素结果可以按照某些算法推算出来,需要计算哪一个就生成哪一个,不比完整的创建元素集合,从而节省大量内存空间 --- Python中一边循环一边计算的机制称为生成器(generator)
在Python中使用yield可以返回函数。使其变成一个生成器
调用函数生成器过程中,每次遇到yield时,函数会暂停执行,并保存当前所有的运行信息,向主调函数出返回结果,并在下一次执行next()方法时从当前位置继续执行
- # 斐波那契数列函数
- def fib(n):
- a, b, c = 0, 1, 0
- while 1:
- if c > n:
- return
- yield a # 将a循环的结果返回给f1,不结束循环
- a, b = b, a + b
- c = c + 1
-
-
- f1 = fib(10)
- for i in f1:
- print(i, end=' ')
-
- 结果:
- 0 1 1 2 3 5 8 13 21 34 55
- def hello():
- print('hello world')
-
-
- hello()
上例定义了一个hello函数,现在需要增加函数功能:
- #第一种
- def hello():
- print('=== start ===')
- print('hello world')
- print('==== end ====')
-
- hello()
-
- #或者
- #第二种
- def hello():
- print('hello world')
-
-
- print('=== start ===')
- hello()
- print('==== end ====')
问题:
第一种方法会改变函数的执行代码,第二种方法如果多次调用,每次都需要增加开始和结束的特效,将会非常消耗机器性能,较为麻烦则能否在不改变还输内部原始代码和参数及调用方式等信息,又想给函数增加新功能?
可以使用装饰器,装饰该函数,在不改变原函数的情况下,增加功能
定义一个函数
- def add(a, b):
- return a + b
调用:
- def add(a, b):
- return a + b
-
-
- print(add(2, 3))
add函数是有返回值的,若输出add不加括号
- def add(a, b):
- return a + b
-
-
- print(add(2, 3))
- print(add)
- print(type(add))
-
- 结果:
- 5
0x0000015F69B0F160> - <class 'function'>
-
结论:
一个函数名称加上括号就会被执行,函数也和整数、字符串、浮点数一样都是一个对象,基于上述理论:
a = print a('hello world') 结果: hello world #解释:把print赋值给a,a('hello world')复制给了print('hello world')改进:
def output(): return print output()('hello world') 结果: hello world #解释:任何返回值都可以在调用时直接替换这个函数 #output()('hello world')中output替换为print等价于print('hello world')再改进:
def output(): print('hello world') def act(func): func() act(output) 结果: hello world #解释:定义一个output函数可以刷出hello world #但没有直接调用,而是写了一个act函数,act函数的参数是一个函数名,作用就是调用act函数时,会间接调用output函数,从而输出hello world
结论:
一个函数名称作为一个函数的参数传递给另一个函数时(实参高阶函数),返回值中包含函数名(返回值高阶函数),这里说的函数名本质为函数首地址,若把一个函数名当做一个参数传递给另一个函数,然后再另一个函数内部做一些操作,则可以实现不修改源代码的情况下,从而变更函数功能。
基于上述演变,得出如下示例
- def deco(func):
- def inner():
- print('=== start ===')
- func()
- print('==== end ====')
-
- return inner
-
-
- def hello():
- print('hello world')
-
-
- hello = deco(hello)
- hello()
-
- 结果:
-
- === start ===
- hello world
- ==== end ====
函数deco即hello会被装入内存,等待被执行
执行hello= deco(hello),抵用deco函数,将hello函数名作为实参传递过去
执行deco(func)函数,其中func等价于hello函数,inner函数装入内存等待被执行,最后返回inner函数名并到hello = deco(hello)函数调用处,hello会被inner覆盖,此时hello就是inner函数
执行hello( )函数,由于hello已被inner覆盖则相当于执行inner( )函数
执行inner函数输出修饰语句,输出func( )函数结果,由于func指向最早的hello函数则输出helloworld
结论:
本段代码本质上修改了调用函数,但表面上未修改调用方式,实现了附加功能,通俗一点来说,就是把函数当做一个盒子,deco是大盒子、inner是中盒子、hello是小盒子,程序将小盒子hello传递给大盒子deco中的中盒子inner,再把中盒子inner执行一次,这就是装饰器
若需要多次则可以多次装饰
- def deco(func):
- def inner():
- print('=== start ===')
- func()
- print('==== end ====')
-
- return inner
-
-
- def hello():
- print('hello world')
-
-
- def nihao():
- print('你好,世界')
-
-
- def py():
- print('牛啊')
-
-
- hello = deco(hello)
- hello()
- nihao = deco(nihao)
- nihao()
- py = deco(py)
- py()
-
- 结果:
- === start ===
- hello world
- ==== end ====
- === start ===
- 你好,世界
- ==== end ====
- === start ===
- 牛啊
- ==== end ====
-
- Process finished with exit code 0
-
器 --- 指的是工具,可以定义成函数
装饰 --- 为其他事无添加额外点缀
装饰器 --- 定义一个函数,该函数是用来为其他函数添加额外功能
应用有切面操作的场景,如 插入日志、性能测试、事务处理、缓存、权限效验等
语法糖 --- 装饰器的语法简化写法
- def deco(func):
- def inner():
- print('=== start ===')
- func()
- print('==== end ====')
-
- return inner
-
-
- @deco # @deco 等价于 hello = deco(hello)
- def hello():
- print('hello world')
-
-
- hello()
- # @deco写在被装饰的def hello()函数之前