python--基础知识点--(1)可迭代对象、迭代器、生成器(2)辨析__iter__、iter

一、概念及关系
1、概念

可迭代对象:实现__iter__方法的类的实例对象。
迭代器:实现__iter__和__next__方法的类的实例对象,两个方法缺一不可。
生成器:调用含有yield关键字的函数会返回一个生成器对象。

2、关系

迭代器一定是可迭代对象,可迭代对象不一定是迭代器。
生成器是一种特殊的迭代器。

二、示例
1、可迭代对象

字符串对象、列表对象、字典对象、元组对象、集合对象都是可迭代对象,但不是迭代器。因为它们都内置实现了__iter__。

from collections import Iterator, Iterable


str_test = "zhangsan"
list_test = ["zhangsan", "lisi", "wangwu"]
dict_test = {"name0": "zhangsan", "name1": "lisi", "name2": "wangwu"}
tuple_test = ("zhangsan", "lisi", "wangwu")
set_test = {"zhangsan", "lisi", "wangwu"}

print(isinstance(str_test, Iterable))
print(isinstance(str_test, Iterator))
print(isinstance(list_test, Iterable))
print(isinstance(list_test, Iterator))
print(isinstance(dict_test, Iterable))
print(isinstance(dict_test, Iterator))
print(isinstance(tuple_test, Iterable))
print(isinstance(tuple_test, Iterator))
print(isinstance(set_test, Iterable))
print(isinstance(set_test, Iterator))


"""
运行结果:
True
False
True
False
True
False
True
False
True
False

Process finished with exit code 0
"""
2、迭代器
(1) iter、__next__自定义迭代器
class Students:
    def __init__(self, names):
        self.names = names
        self.counter = -1

    def __iter__(self):
        print("+++__iter__+++")
        return self

    def __next__(self):
        self.counter += 1
        if self.counter >= len(self.names):
            raise StopIteration
        return self.names[self.counter]


if __name__ == '__main__':
    names = ["zhangsan", "lisi", "wangwu"]
    students = Students(["zhangsan", "lisi", "wangwu"])
    for name in students:
        print(name)
    """
    for...in..过程等同于以下过程
    iter(students)  # 当使用while运行迭代器时可以去掉这条语句,因为students该对象本身就是迭代器,运行结果中也不会有第一行+++__iter__+++
    while True:
        try:
            print(next(students))
        except StopIteration as e:
            break
    """
    from collections import Iterable, Iterator

    print(isinstance(students, Iterator))
    print(isinstance(students, Iterable))


"""
运行结果:
+++__iter__+++
zhangsan
lisi
wangwu
True
True

Process finished with exit code 0
"""

自定义迭代器需注意三点:

  • 必须实现__iter__()方法
  • 必须实现__next__()方法
  • 在__next__()方法中当最后一个元素被迭代出后抛出StopIteration异常
(2)将绑定__getitem__方法的实例对象通过iter转变为迭代器

转该地址查看解析

__getitem__:如果类把某个属性定义为序列,可以使用__getitem__输出序列属性中的某个元素。可以认为绑定__getitem__方法的实例对象为自定义序列对象。

(3) 将序列转化为迭代器
# 以列表为例
list_test = ["zhangsan", "lisi", "wangwu", "zhaoliu"]
list_test = iter(list_test)
while True:
        try:
            print(next(list_test))
        except StopIteration as e:
            break


"""
运行结果:
zhangsan
lisi
wangwu
zhaoliu

Process finished with exit code 0
"""
# 以字典为例
dict_test = {"name0": "zhangsan", "name1": "lisi", "name2": "wangwu""name3": "zhaoliu"}
dict_test = iter(dict_test)
while True:
        try:
            print(next(dict_test))
        except StopIteration as e:
            break


"""
运行结果:
name0
name1
name2
name3

Process finished with exit code 0
"""
3、生成器
def Test(tests):
    for test in tests:
        yield test


if __name__ == '__main__':
    list_test = ["zhangsan", "lisi", "wangwu", "zhaoliu"]
    test_gen = Test(list_test)
    for test in test_gen:
        print(test)


"""
运行结果:
zhangsan
lisi
wangwu
zhaoliu

Process finished with exit code 0
"""

yield详解

三、辨析__iter__、iter
1、iter

迭代协议:绑定__iter__方法的实例对象称为可迭代对象。

2、iter

以下是 iter方法的语法:

iter(object[, sentinel])

object:支持迭代协议的实例对象或支持序列协议的实例对象,否则会返回TypeError异常。

sentinel:传递了第二个参数时。(i) 参数 object 必须是一个能够对内部状态进行维护可调用的对象(如,闭包内函数对象或绑定的__call__方法的实例对象);(ii) iter 创建了一个迭代器对象,每次调用这个迭代器对象的__next__方法时,都会调用 object;(iii) 当__next__的返回值等于哨兵时,就会抛出异常StopIteration。

【注】序列协议:绑定__getitem__方法的实例对象称为自定义序列对象。

(1)只有第一个参数object出现时

只绑定__iter__方法的实例对象一般结合迭代器使用。

class StudentList(object):  # 创建一个类,为了创建对应的可迭代对象
    def __init__(self):
        self.items = []    # 定义一个属性是空列表

    def append(self, name):  # 定义方法可以传参数添加到空列表
        self.items.append(name)

    def __iter__(self):   # 定义iter方法,返回的是对应的可迭代器
        print("++__iter__++")
        return ListIter(self.items)


class ListIter(object):  # 自定义迭代器:作用是记录迭代位置和帮助可迭代对象返回数据
    def __init__(self, items):
        self.items = items  # 保存数据
        self.index = -1  # 记录下标位置

    def __iter__(self):
        return self

    def __next__(self):
        self.index += 1  # 每次使用,下标即+1
        if self.index < len(self.items):
            return self.items[self.index]  # 返回下标数据
        else:
            raise StopIteration  # 抛出异常


if __name__ == '__main__':
    my_list = StudentList()
    my_list.append("zhangsan")
    my_list.append("lisi")
    my_list.append("wangwu")
    my_list.append("zhaoliu")
    for name in my_list:
        print(name)


"""
运行结果:
++__iter__++
zhangsan
lisi
wangwu
zhaoliu

Process finished with exit code 0
"""
(2) 第二个参数sentinel出现时
# (i) object为闭包内函数对象时
def function_out(list_):
    index = -1

    def function_in():
        nonlocal index
        index += 1
        result = list_[index]  # 此处可做一些其它操作
        return result
    return function_in


if __name__ == '__main__':
    names = ["zhangsan", "lisi", "wangwu", "zhaoliu"]
    students = function_out(names)
    for name in iter(students, "wangwu"):  # for...in...内部自动会处理StopIteration异常 
        print(name)


"""
运行结果:
zhangsan
lisi

Process finished with exit code 0
"""
# (2) object为绑定的__call__()方法的实例对象时
class ListIter(object):
    def __init__(self, items):
        self.items = items
        self.index = -1

    def __call__(self):
        self.index += 1
        result = self.items[self.index]  # 此处可以做一些其它操作
        return result


if __name__ == '__main__':
    names = ["zhangsan", "lisi", "wangwu", "zhaoliu"]
    students = ListIter(names)
    for name in iter(students, "wangwu"):
        print(name)


"""
运行结果:
zhangsan
lisi

Process finished with exit code 0
"""

总结:

  • 对于函数来说,闭包可以实现内部函数状态的维护。
  • 对于对象来说,可以通过属性实现对某个方法的内部状态的维护。
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值