Python高阶(二)--- 可迭代对象,迭代器,生成器

可迭代对象

# 可迭代对象: 可以用for操作的对象都是可迭代对象
# list tuple str set dict

for i in [1, 2, 3]:
    print(i)

print(hasattr(list, "__iter__"))  # True
print(hasattr(tuple, "__iter__"))  # True
print(hasattr(str, "__iter__"))  # True
print(hasattr(set, "__iter__"))  # True
print(hasattr(dict, "__iter__"))  # True

迭代器

迭代器协议:
1.迭代器类型必须实现__iter__属性和__next__属性
2.iter 方法必须返回self
3.next 必须返回下一个值,如果没有下一个则抛出StopIterator异常
4.对迭代器进行for操作时,每次操作都会执行__next__函数
5.只能迭代一遍
6.for语句的迭代,会忽略StopIteration异常

from typing import Iterator

obj = range(1, 2)
print(isinstance(obj, Iterator))  # False

obj = iter(range(1, 2))  #把range(1, 2)转换为Iterator类型
print(isinstance(obj, Iterator))  # True

可以看到range(1, 2)不是迭代器,但是iter(range(1, 2))是迭代器

先看一看list的属性

for attr in dir(list):
    print(attr)

重点是__iter__这个属性,这个属性代表是可迭代对象

再看一看obj的属性

for attr in dir(obj):
    print(attr)

在这里插入图片描述
可以看到不仅有__iter__属性,还有__next__这个属性

所以,如何判断某个对象是不是迭代器有两种方法。
方法一:isinstance(obj, Iterator)
方法二:看对象有没有__iter__属性和__next__属性

下面来简单实现一个迭代器

class Next(object):
    def __init__(self, stop, start=0):
        self.start = 0
        self.stop = stop

    def __iter__(self):
        return self

    def __next__(self):
        """
        如果有下一个数,返回下一个数。如果没有下一个数,则抛出StopIteration异常
        :return:
        """
        if self.start >= self.stop - 1:
            raise StopIteration
        else:
            self.start += 1
            return self.start


if __name__ == '__main__':
    obj = Next(5)
    for i in obj:
        print(i)

输出结果:
在这里插入图片描述
每次循环的时候自动执行了__next__函数

快捷键:
在进行迭代的时候,直接输入iter,按回车后:

for  in self:

输入itere,按回车后:

for i,  in enumerate(self):

应用场景

1.存数据1~10000的数据
list:占10000整数的内存
迭代器:占用几个整数的内存

2.爬虫(用Python批量下载图片)
list:把所有的图片都存进去
迭代器:每次获得一张图片,删除上一张图片,把新图片保存

生成器

生成器的意义:为了快速方便的创建一个迭代器,所以生成器一定是一个迭代器。
生成器的使用:yield关键字,在函数中使用。

如果一个函数中有yield关键字,调用函数的时候就不会执行函数的内容,会返回一个对象(这个对象是生成器类)

def f():
    print("1")
    yield 1
    yield 2


if __name__ == '__main__':
    obj = f()  

像这样的话,f就不会执行,不会打印1

现有需求:用迭代器实现平方, 比如传(1,3)返回1 4 9
用正常的写法:

class Squares(object):
    def __init__(self, start, stop):
        self.start = start
        self.stop = stop

    def __iter__(self):
        return self

    def __next__(self):
        if self.start > self.stop:
            raise StopIteration
        current = self.start * self.start
        self.start += 1
        return current
        
if __name__ == '__main__':
    iterator = Squares(1, 3)
    for i, value in enumerate(iterator):
        print(value)

用生成器:

def squares(start, stop):
    for i in range(start, stop + 1):
        yield i * i
        
if __name__ == '__main__':
    iterator = squares(1, 3)
    for i, value in enumerate(iterator):
        print(value)

最简便的方法(自动使用yield):

squares2 = (i * i for i in range(1, 4))

原理
当要访问生成器中的__next__方法时,函数会变成runing状态,当执行完yield时,函数变成非runing状态(挂起)。只有再次执行生成器对象的__next__方法时,函数才会被唤醒。

运用场景

一个image_spider.py文件,他的功能是批量下载网站所有的图片

方法一:

    get_all_urls() 获得网站所有页码对应的url
        urls = []
        return urls
        
    get_all_image_path(url) 获得某url页面中所有的图片地址
        images = []
        return images
        
    download(image_path) 根据图片地址下载图片 
        whit open (...) as f:
            f.write(...)
            
    main:
        urls = get_all_urls() # 获得所有网页的地址
        
        for url in urls:
            img_path_list = get_all_image_path(url) # 获得当前页所有图片
            for img_path in img_path_list:
                download(img_path)
# 太占内存   必须先获取url再执行下面的,有阻塞

方法二:

get_all_image_path() 获得某url页面中所有的图片地址
    image_path = 'http://......'
    yield image_path
    
download(image_path) 根据图片地址下载图片 
    whit open (...) as f:
        f.write(...)
        
main:
    urls = get_all_urls() # 获得所有网页的地址
    
    for url in urls:
        img_path_gen = get_all_image_path(url) # 获得当前页所有图片
        for img_path in img_path_gen:
            download(img_path)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值