python05 - 迭代器,生成器,装饰器
迭代器
迭代器就是访问集合元素的一种方式,迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问一遍后结束。
迭代器很大的特点:
- 只能往前迭代,不能够回退,也不能随机访问其中一个元素,只能通过__next__()方法来进行迭代下一个元素。
- 不需要事先准备大量元素,只有该元素被迭代的时候才会生产这个元素。而在该元素被迭代之前之后,元素是不存在或者被销毁的。这样的特性很适合迭代大型数据。
创建一个迭代器并且迭代:
>>> a=iter(['a',1,3,4,'c','x']) #通过iter类来创建一个迭代对象。
>>> a #只会显示这个迭代对象在内存的地址
<list_iterator object at 0x00000200BDC7ACC0>
>>> a.__next__() #通过next方法来迭代下一个对象
'a'
>>> a.__next__()
1
>>> a.__next__()
3
生成器
说到迭代器,那么就不得不说生成器了,那么什么叫生成器??
一个函数内容包含yield,并且调用这个函数,执行后返回一个迭代对象,那么这个函数就称为生成器。
yield的作用:
在一个函数内,如果有yield,那么此时函数会暂时中断,并把中断的状态保存起来(以便等会重新返回到这个状态),同时也把yield后面的值返回,返回以后再次回到函数内接着执行yield后面的语句。
生成器的特性:
- 生成器其实也是一个函数。
- 生成器通过send方法与外界交互。
- 生成器也有next方法。
那么生成器有什么卵用呢?
我们可以通过yield来做个简单的异步执行(通过yield来实现一个简单的生产消费者模型)
import time
def a(name): #定义一个消费者
print("Begin eat")
while 1:
baozi = yield # 把yield的值赋值给baozi
print("%s eat %s"%(name,baozi))
def b(): #定义一个生产者
c=a('ljf')
c.__next__() #调用生成器的next方法
for i in range(1,10):
c.send(i) #调用生成器的send方法与外界交互,通过send方法把i 的值赋值给yield
print("begin shengcan")
time.sleep(2)
b()
装饰器
什么是装饰器呢?从字面上简单的理解就是装饰用的器具,哈哈,其实深入是这样的概念:
所谓装饰器仅仅是一种语法糖, 可作用的对象可以是函数也可以是类, 装饰器本身是一个函数, 其主要工作方式就是将被装饰的类或者函数当作参数传递给装饰器函数, 从而达到一个装饰的效果,我们使用@符号来调用装饰圈。
说到这里,我们得再提下这个原则:
开放封闭原则
虽然这个原则是作用在面向对象的开发,但是同样适用于面向过程的开发,既已实现功能的代码不允许更改,只允许在外部进行扩展。
- 开放:对扩展开发
- 封闭:已经实现功能的代码不允许更改
应用场景:
比如公司新开发好的一个基础运维平台,每个部门都可以去调用这个平台,但是调用的时候不需要验证,那么此时boss提出要求需要添加验证在调用功能之前,此时我们有三个方案:
- 让每个调用者的代码添加验证功能
- 在基础运维平台的每个功能里面添加验证功能的代码
如 :
def f1():
验证 #在原有的代码上插入这段验证的代码
xxx:
def f2():
验证 #同上
xxx:
3 把验证代码封装成一个函数或类,在每个功能里面添加 调用 验证代码
如:
def yanzheng(): #定义一个验证的函数
sssss
def f1():
yanzheng() #在原来的代码调用这个验证的函数
xxx
def f2():
yanzheng() #同上
xxx
自己仔细想想,上面第一个方案是不可行的,因为会牵涉到多个部门更改代码,第二第三个方案是不遵循开放封闭原则,好了,此时装饰器就派上用场了。我们先看代码,再说执行流程
我们先来看代码的演变过程:
最简单的代码
def yanzheng(func):
print("authtication your password!!") #使用最简单的print来替代真正的验证代码段
return func('ljf')
@yanzheng #这里的@yanzheng==yanzheng(test) 把函数作为参数传入yanzheng这个函数里面
def test(name):
print("was be decorator!!")
print('name : %s'%name)
这个段代码有个弊端就是是一运行就会执行yanzheng这个函数的。所以这代码还得改进,改进到等我们调用的时候在执行。
那么就有下面这段代码:
进阶代码
def yanzheng(func):
def warrer(name): #我们在yanzheng这个函数里面再嵌套一层函数并且return 嵌套的函数,这样的话当调用yanzheng的时候,就不 会自动运行test这个函数了。
print("authtication your password!!")
return func(name)
#return func('ljf')
return warrer
@yanzheng
def test(name):
print("was be decorator!!")
print('name : %s'%name)
test('ljf')
那问题来了,如果我函数里面要传入多个参数的时候,那么该怎么处理了呢?
接下来就展现成功修饰的代码,我们加入动态参数:
def yanzheng(func):
def warrer(*args): #这里使用*args来动态的传入参数,还可以调用**kwargs来传入字典
print("authtication your password!!")
return func(*args)
return warrer
@yanzheng
def test(name):
print("was be decorator!!")
print('name : %s'%name)
@yanzheng
def test1(name,age):
print("was be decorator2!!")
print('name %s,age: %s'%(name,age))
test('ljf')
test1('liaojaifa',24) #调用的时候直接传入实参,都是ok没有问题的
打印效果如下:
authtication your password!!
was be decorator!!
name : ljf
authtication your password!!
was be decorator2!!
name liaojaifa,age: 24