python基础篇_005_迭代器和生成器

Python迭代器和生成器

1.迭代器

迭代:可以将某个数据集内的数据“一个挨着一个的取出来”

for i in range(1, 10, 2):  # in 后面的对象必须是一个可迭代的
    print(i)  # 从可迭代对象中将元素一个一个取出
"""
判断是否可迭代
"""
from collections import Iterable

str1 = 'adc'
l = [1, 2, 3, 4]
t = (1, 2, 3, 4)
d = {1: 2, 3: 4}
s = {1, 2, 3, 4}
print(isinstance(str1, Iterable))
print(isinstance(l, Iterable))
print(isinstance(t, Iterable))
print(isinstance(d, Iterable))
print(isinstance(s, Iterable))  # True

int1 = 1234
print(isinstance(int1, Iterable))  # False

2.可迭代协议

可以被迭代要满足的要求就叫做可迭代协议。内部实现了__iter__方法。

print(dir(str))  # 可迭代,内部要有一个__iter__()方法
print(str1.__iter__())
#['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmod__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'capitalize', 'casefold', 'center', 'count', 'encode', 'endswith', 'expandtabs', 'find', 'format', 'format_map', 'index', 'isalnum', 'isalpha', 'isdecimal', 'isdigit', 'isidentifier', 'islower', 'isnumeric', 'isprintable', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'maketrans', 'partition', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill']
#<str_iterator object at 0x0000000000A6DB38>
str_iterator

iterator 就是迭代器
str1 = 'abc'
dir(str1)  # 列出所有字符串实现的方法
set1 = set(dir(str1))
set2 = set(dir(str1.__iter__()))
print(set2 - set1)
#  {'__length_hint__', '__next__', '__setstate__'}

迭代器多了三个方法

"""迭代器中的方法作用"""
str1 = 'abc'
# 获取迭代器
iter_1 = str1.__iter__()
# 获取迭代器中元素的长度
print(iter_1.__length_hint__())  # 3
# 根据索引值指定从哪里开始迭代
print(iter_1.__setstate__(1))  # None
# 一个一个的取值
print(iter_1.__next__())     # b  for 循环内部调用 实现一个一个取值

自己实现迭代取数:

str1 = 'abc'
# 获取迭代器
iter1 = str1.__iter__()

# 循环取出
while 1 :
    a = iter1.__next__()
    print(a)
# a
# b
# c
# 
# Traceback (most recent call last):
#   File "E:/Python/d01/函数.py", line 8, in <module>
#     a = iter1.__next__()
# StopIteration

异常机制处理异常:

str1 = 'abc'
# 获取迭代器
iter1 = str1.__iter__()

# 循环取出
while 1:
    try:
        a = iter1.__next__()
        print(a)
    except StopIteration:
        break
# a
# b
# c

3.生成器

实现迭代器功能的东西就是生成器

Python中提供的生成器:

1.生成器函数:常规函数定义,但是,使用yield语句而不是return语句返回结果。yield语句一次返回一个结果,在每个结果中间,挂起函数的状态,以便下次从它离开的地方继续执行

2.生成器表达式:类似于列表推导,但是,生成器返回按需产生结果的一个对象,而不是一次构建一个结果列表

生成器Generator:

  本质:迭代器(所以自带了__iter__方法和__next__方法,不需要我们去实现)

  特点:惰性运算,开发者自定义

生成器函数

1.生成器函数:一个包含yield关键字的函数就是一个生成器函数。
2.yield与reduce区别:
  yield可以为我们从函数中返回值,但是yield又不同于return,return的执行意味着程序的结束,调用生成器函数不会得到返回的具体的值,
  而是得到一个可迭代的对象。每一次获取这个可迭代对象的值,就能推动函数的执行,获取新的返回值。直到函数执行结束。
def genrator_f1():
    a = 1
    print('a变量')
    yield a
    b = 2
    print('b变量')
    yield b


g1 = genrator_f1()    #  g1获取的是生成器
print(g1.__next__())  
print(g1.__next__())
print(g1.__next__())

# a变量
# 1
# b变量
# 2
# Traceback (most recent call last):
#   File "E:/Python/d01/test.py", line 14, in <module>
#     print(g1.__next__())
# StopIteration

生成器的优点:不会在内存中瞬间生成很多数据

def produce():
    for i in range(10):
        yield "生产序列号:%d" % i


# 获取生成器
pro_g = produce()
print(pro_g.__next__())   # 一个一个获取
print(pro_g.__next__())
print(pro_g.__next__())

num = 0             # 批量获取
for i in pro_g:
    print(i)
    num += 1
    if num == 5:
        break
# 生产序列号:0
# 生产序列号:1
# 生产序列号:2
# 生产序列号:3
# 生产序列号:4
# 生产序列号:5
# 生产序列号:6
# 生产序列号:7

实现日志实时监控: Linux tail -f 

import time


def tail(filename):
    with open(filename,mode='r',encoding='utf-8') as f:
        f.seek(0, 2)  # 从文件末尾算起
        while True:
            line = f.readline()  # 读取文件中新的文本行
            if not line:
                time.sleep(1)
                continue
            yield line


tail_g = tail('C:\Users\18047463\Desktop\test.txt')
for line in tail_g:
    print(line.strip())

实时计算平均数:

def averager():
    total = 0.0
    count = 0
    average = None
    while 1:
        term = yield average
        total += term
        count += 1
        average = total / count


g_avg = averager()
g_avg.__next__()  # 初始化
while 1:
    num = input(">>>")
    if num == 'q':
        break
    print(g_avg.send(int(num)))

初始化使用装饰器:

from functools import wraps


def init(func):
    @wraps(func)
    def inner(*args, **kwargs):
        g = func(*args, **kwargs)
        g.__next__()
        return g

    return inner


@init
def averager():
    total = 0.0
    count = 0
    average = None
    while 1:
        term = yield average
        total += term
        count += 1
        average = total / count


g_avg = averager()
while 1:
    num = input(">>>")
    if num == 'q':
        break
    print(g_avg.send(int(num)))
def gen1():
    for c in 'AB':
        yield c
    for i in range(3):
        yield i


print(list(gen1()))


def gen2():
    yield from 'AB'
    yield from range(3)


print(list(gen2()))

列表推导式和生成器表达式

egg_list=['鸡蛋%s' %i for i in range(10)]  #列表解析
print(egg_list)
# ['鸡蛋0', '鸡蛋1', '鸡蛋2', '鸡蛋3', '鸡蛋4', '鸡蛋5', '鸡蛋6', '鸡蛋7', '鸡蛋8', '鸡蛋9']
laomuji=('鸡蛋%s' %i for i in range(10))  #生成器表达式  相比列表解析,更加节省内存
print(laomuji)  # <generator object <genexpr> at 0x00000000013F8780>
print(next(laomuji)) #next本质就是调用__next__
print(laomuji.__next__())
print(next(laomuji))
原文地址:https://www.cnblogs.com/yin-fei/p/10763702.html