Python 函数基础4 迭代器、生成器、枚举类型

今日目录:

  • 1.迭代器
  • 2.可迭代对象
  • 3.迭代器对象
  • 4.for循环迭代器
  • 5.生成器
  • 6.枚举对象

一、迭代器:

循环反馈的容器(集合类型)
每次重复即一次迭代,并且每次迭代的结果都是下一次迭代的初始值
l = [1, 2, 3]
count = 0
while count<len(l):
    print(l[count])
    count += 1
View Code
1.1 为什么要有迭代器?
字符串、列表、元组可以通过索引的方式迭代取出其中包含的元素
字典、集合、文件等类型,没有索引,只有通过不依赖索引的迭代方式才能取值,即迭代器

二、可迭代对象

2.1 什么是可迭代对象
可迭代对象指的是内置有__iter__()方法的对象,即obj.__iter__()
str,list,tuple,dict,set,range(),file,迭代器对象,enumerate(),生成器都是可迭代对象,即:
[].__iter__()
{}.__iter__()
().__iter__()
{1,2}.__iter__()
   ......
View Code

三、迭代器对象

3.1 什么是迭代器对象
可迭代对象通过调用__iter__()方法得到迭代器对象
迭代器对象可以不依赖索引取值(一次从容器中取出一个值) 
迭代器对象都有__next__方法,且通过该方法获取容器中的值,获取规则,从前往后一次一个
3.2 有哪些迭代器对象
文件类型、enumerate()、生成器是迭代器对象
open('a.txt').__iter__()
open('a.txt').__next__()
ps:    
    1.迭代器对象去一个值就少一个值
    2.取完了再取会报错  --> 可通过try对异常进行捕获,并处理
    3.上一个迭代器对象迭代取值完毕后,就取空了,如果要再取值,要重新生成迭代器对象
    4.迭代器对象不能求长度(内部值的个数)
    5.迭代器对象一定是可迭代对象,而可迭代对象不一定时迭代器对象
# 迭代器对象
iter_obj = st1.__iter__()
print(iter_obj)  # <set_iterator object at 0x0000025B85231CF0>

print([1, 2, 3].__iter__())  # <list_iterator object at 0x0000017694B0B860>

# 迭代器对象去一个值就少一个值
print(iter_obj.__next__())  # 9
print(iter_obj.__next__())  # 2
print(iter_obj.__next__())  # 3
print(iter_obj.__next__())  # 4
print(iter_obj.__next__())  # 7
# print(iter_obj.__next__())  # 7  # 异常 StopIteration
View Code
# 迭代器无法求长度(内部值的个数)
while True:
    try:  
        val = iter_obj2.__next__()
        print(val)
    except StopIteration:
        break
View Code

四、for 循环迭代器

自带异常处理的while循环,自动获取被迭代的对象的迭代器对象
原理:
    1.执行in后面对象的dic.__iter__()方法,得到一个迭代器对象iter_dic
    2.执行next(iter_dic),将得到的值赋值给k,然后执行循环体代码
    3.重复过程2,直到捕捉到异常,StopIteration,结束循环
迭代器的优缺点:
    1.优点
        提供一种统一的、不依赖于索引的迭代方式
        惰性计算,节省内存
    2.缺点
        无法获取长度(只有在next完毕才知道到底有几个值)
        一次性的,只能往后走,不能往前退
# for 循环迭代器,自带异常处理的while循环,自动获取被迭代的对象的迭代器对象
iter_obj = st1.__iter__()
for item in iter_obj:
    print(item)
print('----------------华丽的分割线-----------------------------------------------')

for item1 in st1:
    # 自动完成for item in st1.__iter__()
    # 自动完成异常处理
    print(item1)
View Code

五、生成器

包含yield关键字的函数就是生成器
def fn():
    yield 'good'
    
该函数名()得到的是生成器对象,且不会执行函数体

生成器的应用案例
当访问的数据资源过大,可以将数据用生成器处理,一次只获取所有内容的一条资源
def g_fn():
    print("!!!!!!!!!!!!!!!!!!!!")
    yield '第一个'

    print('@@@@@@@@@@@@@@@@@@@@@')
    yield '第二个'

    print('#####################')
    yield '第三个'

    print('$$$$$$$$$$$$$$$$$$$$$')
    yield '第四个'


g_obj = g_fn()

# 在函数内部执行一次,在遇到下一个yield时停止,且可以拿到yield的返回值
r1 = g_obj.__next__()
print(r1)

# 从上一次停止的地方继续往下走,再遇到下一个yield的时候停止,且可以拿到yield的返回值
r2 = g_obj.__next__()
print(r2)

r3 = g_obj.__next__()
print(r3)
View Code
# 重新定义一个range()生成器

def my_range(min, max, step=1):
    # min, max = max, min
    tag = min
    while True:
        if tag >= max:
            break
        yield tag
        tag += step


range_obj = my_range(5, 10, 1)

for i in range_obj:
    print(i)
View Code

六、枚举对象

枚举对象:通过enumerate()方法,可以为可迭代对象生成迭代索引,其本身也是一个迭代器对象

作业:
# 1.用生成器完成自定义range方法,可以完成系统range的所有功能


def my_range(min, max= 0, step=1):

    if step > 0:  # 步长为正的
        if max == 0:  # 如果最大值为 0 --> my_range(10)
            min, max = max, min
        tag = min
        while True:
            if tag >= max:
                break
            yield tag
            tag += step

    elif step < 0:  # 步长为负的
        tag = min
        if min > max:
            while True:
                if tag <= max:
                    break
                yield tag
                tag += step

    else:   # 第三个参数不能是 0
        print("第三个参数不能是 0 !")


range_obj1 = my_range(10, 1, -2)
range_obj2 = my_range(10)  # --------可以用
range_obj3 = my_range(2, 10)  # -----可以用
range_obj4 = my_range(2, 10, 2)  # --可以用


"""
for i in range_obj1:
    print(i)
"""
View Code
# 2.用生成器完成自定义enumerate方法,也可以为可迭代对象提供索引支持
# 不判断,和系统一样,传非迭代对象抛异常
def my_enumerate(iterable, start=0):
    for v in iterable:
        yield (start, v)
        start += 1

# 判断,那么传入b1,b2以外的情况也不抛异常
def my_enumerate(iterable, start=0):
    # str, list, tuple, set, dict 五个基础
    b1 = isinstance(iterable, (str, list, tuple, set, dict))
    # 处理字典的keys,values,items
    b2 = type(iterable) in [type({}.keys()), type({}.values()), type({}.items())]
    if b1 or b2:
        for v in iterable:
            yield (start, v)
            start += 1
    else:
        yield '暂不能处理'

for v in my_enumerate({'a': 1}.items(), 100):
    print(v)
View Code
# 3.用生成器完成获取阶乘得方法,第一次next得到1的阶乘,第二次next得到2的阶乘,依次类推,直接for循环,可以依次得到指定范围内得所有阶乘,eg:factorial(10),可以得到1~10之间的10个阶乘
def factorial(num):
    pro = 1
    for i in range(1, num + 1):  # 完成累积
        pro *= i
        yield pro
        
for v in factorial(5):
    print(v)
View Code

 

2019.04.05 添加

迭代器、生成器。可迭代对象  官方定义:

# generator -- 生成器
# 返回一个 generator iterator 的函数。
# 它看起来很像普通函数,不同点在于其包含 yield 表达式以便产生一系列值供给 for-循环使用或是通过 next()
# 函数逐一获取。


# iterable -- 可迭代对象
"""
能够逐一返回其成员项的对象。
可迭代对象的例子包括
所有序列类型(例如 list、str 和 tuple)以及某些非序列类型例如 dict、文件对象 以及定义了 __iter__() 方法
或是实现了 Sequence 语义的 __getitem__() 方法的任意自定义类对象。


iterable -- 可迭代对象
可迭代对象被可用于 for 循环以及许多其他需要一个序列的地方(zip()、map() ...)。
当一个可迭代对象作为参数传给内置函数 iter() 时,它会返回该对象的迭代器。
这种迭代器适用于对值集合的一次性遍历。
在使用可迭代对象时,你通常不需要调用 iter() 或者自己处理迭代器对象。
for 语句会为你自动处理那些操作,创建一个临时的未命名变量用来在循环期间保存迭代器。
参见 iterator、sequence 以及 generator。


iterator -- 迭代器
用来表示一连串数据流的对象。
重复调用迭代器的 __next__() 方法(或将其传给内置函数 next())将逐个返回流中的项。
当没有数据可用时则将引发 StopIteration 异常。
到这时迭代器对象中的数据项已耗尽,继续调用其 __next__() 方法只会再次引发 StopIteration 异常。
迭代器必须具有 __iter__() 方法用来返回该迭代器对象自身,因此迭代器必定也是可迭代对象,可被用于其他可迭代对象适用的大部分场合。
一个显著的例外是那些会多次重复访问迭代项的代码。
容器对象(例如 list)在你每次向其传入 iter() 函数或是在 for 循环中使用它时都会产生一个新的迭代器。
如果在此情况下你尝试用迭代器则会返回在之前迭代过程中被耗尽的同一迭代器对象,使其看起来就像是一个空容器。


迭代器类型介绍:
https://docs.python.org/zh-cn/3.7/library/stdtypes.html#typeiter

"""
View Code

 

posted @ 2019-04-03 20:21  xt12321  阅读(286)  评论(0编辑  收藏  举报