Python - 迭代器和解析

可迭代对象

__iter__ 方法的类产生的对象为可迭代对象

如何判断一个对象可迭代?

from collections.abc import Iterable

class MyClass:

    def __iter__(self):
        pass

if __name__ == '__main__':
    my_class = MyClass()
    print(isinstance(my_class, Iterable))  # out: True

自定义可迭代对象

class MyList:
    def __init__(self):
        self.list = []

    def add_item(self, data):
        self.list.append(data)

    # 返回迭代器
    def __iter__(self):
        # 创建自定义迭代器
        return MyListIterator(self.list)


class MyListIterator:
    """自定义迭代器类"""
    def __init__(self, my_list):
        self.list = my_list
        self.current_index = 0

    def __next__(self):
        """返回下一个元素"""
        if self.current_index < len(self.list):
            ret_el = self.list[self.current_index]
            self.current_index += 1
            return ret_el
        else:
            raise StopIteration


if __name__ == '__main__':
    my_list = MyList()
    my_list.add_item('张飞')
    my_list.add_item('关于')
    my_list.add_item('诸葛亮')
    for var in my_list:
        print(var)

__next__方法:

next__方法会迭代一次,到达最后会引发StopIteration异常,
任何这类对象都能以 for循环或其他迭代工具遍历,所有迭代工具内部工作起来都时在每次迭代时调用__next
()
并捕捉StopIteration异常来进行离开

文件迭代器

1.pen() 函数返回的是一个可迭代的对象 ,可以与for 循环结合使用
2. readline() 方法会调用__next__() 方法读取一行数据
3. 到文件末尾时,next()会引发内置的StopIteration异常, readline()返回空字符串

>>> f = open('10_session.py', encoding='utf-8')
>>> f.readline()
'import requests\n'
>>> f.readline()
'\n'
>>> f.__next__()
'# 在一次session会话中,可以自动保存服务器产生的cookies 信息,并且自动在下一条请求时附加\n'
>>> f.__next__()
'session = requests.session()\n'
>>>

>>> for line in open('10_session.py', encoding='utf-8'):
...     print(line)
...
import requests

session = requests.session()

url = 'http://httpbin.org/cookies/set/sessioncookie/123456789'

session.get(url)

r = session.get("http://httpbin.org/cookies")

print(r.json())

手动迭代:iter()和next()

iter(可迭代对象): 返回一个迭代器
next(迭代器): 会自动调用__next__方法,向后迭代一次
next(迭代器) 等价于 迭代器.__next__()

>>> L  = [1,2,3,4]
>>> I = iter(L)
>>> type(I)
<class 'list_iterator'>
>>> next(I)
1
>>> next(I)
2
>>> next(I)
3
>>> next(I)
4
>>> next(I)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration
>>>

>>> f = open('10_session.py')
>>> iter(f) == f
True

列表解析

其语法源自于集合理论表示法中的一个结构,该结构对集合中的每个元素应用一个操作。
列表解析写在一个方括号中,因为它们最终构建的是一个新的列表,以一个自定义表达式开始,
后面接一个for循环,自定义表达式用于处理每一次迭代的元素
列表解析的优点:
比手动的for循环语句快一倍,因为它们的迭代内部是以C语言的速度执行的,对于较大的数据集合,更能发挥出速度的优势

>>> L = [1,2,3,4]
>>>
>>> data = [x+10 for x in L]
>>> data
[11, 12, 13, 14]
>>>

在文件上使用列表解析

当我们会在序列上的每一项进行操作的时候就可以考虑使用列表解析

>>> f = open('scripts.py')
>>> f.readlines()
['import sys\n', 'print(sys.path)\n', 'x = 2\n', 'print(x ** 33)\n']

# 去除每一行结尾的空白
>>> data = [ line.rstrip() for line in open('scripts.py')]
>>> data
['import sys', 'print(sys.path)', 'x = 2', 'print(x ** 33)']
>>>

列表解析扩展

  1. 表解析中for 循环后面可以跟一个if 表达式,来过滤掉一部分结果、
    2.列表解析也可以变得更复杂,比如嵌套for循环, 多个for子句,
    每个for 子句又可以有一个相关的if子句
# 过滤掉不是p 开头的行
>>> [ line.rstrip() for line in open('scripts.py') if line[0] == 'p']['print(sys.path)', 'print(x ** 33)']

# 多个for子句的情况
>>> [x+y for x in 'abc' for y in '123']
['a1', 'a2', 'a3', 'b1', 'b2', 'b3', 'c1', 'c2', 'c3']

集合解析

>>> set(open('scripts.py'))
{'print(x ** 33)\n', 'import sys\n', 'print(sys.path)\n', 'x = 2\n'}
>>> {line for line in open('scripts.py')}
{'print(x ** 33)\n', 'import sys\n', 'print(sys.path)\n', 'x = 2\n'}

字典解析

>>> {key:value for (key,value) in enumerate(open('scripts.py'))}
{0: 'import sys\n', 1: 'print(sys.path)\n', 2: 'x = 2\n', 3: 'print(x ** 33)\n'}
posted @ 2022-01-03 15:34  chuangzhou  阅读(40)  评论(0编辑  收藏  举报