python笔记-迭代器、生成器、装饰器
- 迭代器
- 自定义迭代器
- 迭代器的应用
- 生成器
- 创建生成器
- 装饰器
- 创建装饰器
- 无参数的函数装饰器
- 被装饰函数无参数无返回值
- 被装饰函数带参数无返回值
- 被装饰函数有参数,有返回值
- 带参数的装饰器
- 无参数的函数装饰器
- 使用类来定义装饰器
- 使用装饰器
- 创建装饰器
迭代器
迭代的意思类似于循环,每一次重复的过程被称为一次迭代的过程,而每一次迭代的结果会被用来作为下一次迭代的初始值。提供迭代方法的容器称为迭代器
迭代器是一个可以记住遍历位置的对象,它从第一个元素开始访问,直到所有的元素被访问完结束
可迭代对象,需要使用迭代器输出每个元素;
判断一个对象是否是可迭代对象,看该对象定义时是否定义了 iter() 方法
通过 obj.__ dir __()查看对象的所有属性和方法
迭代器有两个基本的方法:iter() 和 next()
- iter()方法用来创建迭代器对象
- next()方法用于遍历对象的元素
创建迭代器.使用 iter(),并输出元素
mylist=[1,2,3,4]
l = iter(mylist)
print(next(l))
输出
1
使用next()如果超出了元素长度,程序会报错:StopIteration
还可以通过for循环和while输出元素
list1=[1,2,3,4,5]
l=iter(list1) #生成迭代器
# for 循环
for i in l:
print(i)
# while循环
while True:
try:
print(next(l))
except:break
1
2
3
4
5
自定义迭代器
迭代器也是对象,对象是由类实例化生成的,所以需要一个迭代器类来生成迭代器
在定义类时,同时定义 __ iter__() 和 __ next __ () 方法,这个类就被视为 迭代器类
有了迭代器类,还要定义一个可迭代的类,在可迭代的类的__iter__()方法里面使用自定义的迭代器类实现迭代过程
class myListIterator:
def __init__(self,data):
self.data=data
self.now = 0
def __iter__(self):
'''返回该对象的迭代器类的实例,因为自己就是迭代器,所以返回自己'''
return self
def __next__(self):
"""判断,遍历超出边界抛出异常"""
while self.now < self.data:
self.now+=1
return self.now - 1
raise StopIteration
class Mylist:
def __init__(self,num):
self.data=num
def __iter__(self):
return myListIterator(self.data)
my_list=Mylist(5)
my_list_iter=iter(my_list)#转换为迭代器的实例化对象
for i in my_list_iter:
#迭代输出每个元素
print(i)
看起来这个调用过程:Mylist类是负责接收数据,然后传给迭代器类进行一些处理之后再以迭代器实例返回来,作为自己迭代的返回值;就是两个类之间的调用吧,现目前自己是这么理解的。
迭代器的应用
为什么使用循环遍历也能输出列表的元素,还需要用得迭代器?
当数据量太大的时候,普通遍历是把列表的所有数据存入内存,所以可以多次循环,会占用内存,降低程序运行速度;
而使用迭代器,迭代器只会去当前迭代的数据,只这样就能节省内存的开销,提高程序的运行速度,它在大文件的读取、大数据处理和网站大量数据爬取的情况下具有明显的优势
python 内置itertools模块,提供了多种迭代器工具:
- 无限迭代器
- 迭代短序列
- 组合迭代序列
生成器
使用了关键字 yield 的函数 就称为生成器,它返回的是一个迭代器
创建生成器
* 函数使用yield关键字
* 将列表推导式(生成式)的中括号[] 改为 小括号()
示例1
mylist=[0,1,2,3,4,5,6,7,8,9]
b=(i+2 for i in mylist)
print(type(b))
输出:
示例2:
def Gen():
for i in range(5,30,5): # 5,10,15,20,25
yield i*10
myre=Gen()
for j in myre:
print(j)
输出:
50
100
150
200
250
装饰器
当我们完成函数方法或类的功能定义后,如果发现还要添加额外的功能,在不重新定义的情况下,可以为函数方法或类添加装饰器
装饰器可以通过 类 和 函数 定义,分别叫做 类装饰器 和 函数装饰器
创建装饰器
装饰器的实质,是闭包。
闭包的特点是:有内嵌函数,且内嵌函数引用的外部函数的变量,外部函数返回值为内嵌函数。
也就是说装饰器是一个函数,且内部还有一个函数。
无参数的函数装饰器
被装饰函数无参数无返回值
示例:
def set_function(fun):
def call_function():
print("这是闭包函数")
print(f"参数fun 的值为:{fun}")
fun()
return call_function
@set_function
def myDef():
print("---running---")
if __name__=='__main__':
myDef()
输出:
这是闭包函数
参数fun 的值为:
---running---
被装饰函数带参数无返回值
装饰器内部函数的传参,应该与被装饰函数的传参保持一致
示例:myDef(),传递一个参数
def set_function(fun):
def call_function(num):# 传参与被装饰函数的传参保持一致
print("这是闭包函数")
print(f"参数fun 的值为:{fun}")
print(f"参数num 的值为:{num}")
fun(num)
return call_function
@set_function
def myDef(num):
print("---running---")
if __name__=='__main__':
myDef(12)
被装饰函数有参数,有返回值
装饰器内部函数的传参 与 被装饰函数 的 传参保持一致;
内部函数的返回值为: 被装饰函数的调用过程
同时使用两个或者两个以上装饰器,无论被装饰函数有没有返回值,装饰器 内层函数都必须设置返回值
示例:内部函数的返回值为被装饰函数的调用过程
def set_function(fun):
def call_function(num):# 传参与被装饰的函数保持一致
print("这是闭包函数")
print(f"参数fun 的值为:{fun}")
print(f"参数num 的值为:{num}")
return fun(num)
return call_function
@set_function
def myDef(num):
print("---running---")
return num+3
if __name__=='__main__':
m = myDef(10)
print(f"返回值为:",m)
输出:
这是闭包函数
参数fun 的值为:
参数num 的值为:10
---running---
返回值为: 13
带参数的装饰器
要在装饰器中设置参数,整个装饰器需要定义3层函数
- 第一层函数负责接收装饰器的参数,返回值为第2层函数
- 第二层函数负责接收被装饰的函数,返回值为第3层函数
- 第三次函数根据需要获取外两层的参数,并负责调用被装饰函数,返回值为被装饰函数的调用过程
示例:
def info(value):
def decorator(func):
def wrapper(*args,**kwargs):
print(value)
return func(*args,**kwargs)
return wrapper
return decorator
@info('nebulaaaaaa')
def sayHello():
print("你好世界!")
if __name__=='__main__':
sayHello()
输出
nebulaaaaaa
你好世界!
使用类来定义装饰器
只需定义初始化方法__init__() 和 内置方法__call__()
定义无参数装饰器
class mydecorator:
def __init__(self,func):
self.func=func
return
def __call__(self):
self.func()
@mydecorator
def sayHello():
print("Hello,world")
if __name__=='__main__':
sayHello()
输出:
Hello,world
定义有参数装饰器
class mydecorator:
def __init__(self,para): #接收装饰器的参数
self.para=para
def __call__(self,func): #接收被装饰的函数,返回值为内层函数
print(self.para)
def wrapper(*args,**kwargs): #负责调用被装饰函数,返回值为被装饰函数的调用过程
return func(*args,**kwargs)
return wrapper
@mydecorator('Lily')
def sayHello():
print("It's time to go home")
if __name__=='__main__':
sayHello()
输出:
Lily
It's time to go home
使用装饰器
-
在需要被装饰的函数上一行 以@+装饰器函数的名称表示,不用加括号
-
执行顺序以设置的顺序,从上往下执行
在类中使用装饰器,如果装饰器需要调用类中的属性和方法, 只需要增加一个参数 self.