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))

输出:

<class 'generator'>

示例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 的值为:<function myDef at 0x00000180F3C1DA60>
---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 的值为:<function myDef at 0x000001DB4BD8DA60>
参数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.

posted @ 2021-12-27 17:47  深海鱼香茄子  阅读(32)  评论(0编辑  收藏  举报