zoukankan      html  css  js  c++  java
  • python-

    目录

    • 迭代器
      • python中的for循环
      • 迭代和可迭代协议
      • 为什么要有for循环
    • 生成器
      • 初识生成器
      • 生成器函数
    • 列表推导式和生成器表达式
    • 本章小结
    • 生成器相关的面试题

    1,迭代器

    1.1 python中的for循环

    要了解for循环是怎么回事儿,还是要从代码的角度出发。
    首先,对一个列表进行for循环。

    for i in [1, 2, 3, 4]:
        print(i)
    
    # 结果呈现
    1
    2
    3
    4
    

    上面这段代码肯定是没有问题的,但是我们换一种情况,来循环一个数字1234试试

    for i in 1234:
        print(i)
    
    # 结果呈现
    Traceback (most recent call last):
      File "C:/Users/thinkpad/Envs/daily_test/test_project/test_file.py", line 1, in <module>
        for i in 1234:
    TypeError: 'int' object is not iterable
    
    

    报错了!“TypeError: 'int' object is not iterable” ,说int类型不是一个iterable,那这个iterable是个啥?

    1.2 迭代和迭代协议

    1.2.1 什么是迭代

    • 首先,我们从报错来分析,“iterable”叫做“可迭代的”概念,之所以1234不可以for循环,是因为它不可迭代。那么如果“可迭代”,就应该可以被for循环了。
    • list dic str set tuple f = open() range() enumerate都可以被for循环,说明他们都是可迭代的。
    from collections import Iterable
    # 注: 该模块的调用,将在python3.8 开始停止使用
    
    l = [1, 2, 3, 4]
    t = (1, 2, 3, 4)
    d = {1: 2, 3: 4}
    s = {1, 2, 3, 4}
    
    print(isinstance(l, Iterable))
    print(isinstance(t, Iterable))
    print(isinstance(d, Iterable))
    print(isinstance(s, Iterable))
    
    # 结果呈现
    True
    True
    True
    True
    
    • 结合使用for循环取值的现象,再从字面上理解一下,其实迭代就是可以将某个数据集内的数据“一个挨着一个的取出来”,就叫做迭代。

    1.1.2 可迭代协议

    • 现在是从结果分析原因,能被for循环的就是“可迭代的”,但是如果正着想,for怎么知道谁是可迭代的呢?

    • 假如我们自己写了一个数据类型,希望这个数据类型里的东西也可以使用for被一个一个的取出来,那我们就必须满足for的要求。这个要求就叫做“协议”。

    • 可以被迭代要满足的要求 就叫做 可迭代协议。可迭代协议的定义非常简单,就是内部实现了__iter__方法。

    • print(dir([])) 打印列表拥有的所有方法

      • 双下划线的方法双下方法
    # python 解释器在执行 '+' 时,实际上调用的是 ````__add__```` 方法 
    print([1] + [2])
    print([1].__add__([2]))
    
    # 结果呈现
    [1, 2]
    [1, 2]
    
    • 接下来验证一下:
    print(dir([1,2]))
    print(dir((2,3)))
    print(dir({1:2}))
    print(dir({1,2}))
    
    # 结果呈现
    ['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
    ['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'count', 'index']
    ['__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'clear', 'copy', 'fromkeys', 'get', 'items', 'keys', 'pop', 'popitem', 'setdefault', 'update', 'values']
    ['__and__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__iand__', '__init__', '__init_subclass__', '__ior__', '__isub__', '__iter__', '__ixor__', '__le__', '__len__', '__lt__', '__ne__', '__new__', '__or__', '__rand__', '__reduce__', '__reduce_ex__', '__repr__', '__ror__', '__rsub__', '__rxor__', '__setattr__', '__sizeof__', '__str__', '__sub__', '__subclasshook__', '__xor__', 'add', 'clear', 'copy', 'difference', 'difference_update', 'discard', 'intersection', 'intersection_update', 'isdisjoint', 'issubset', 'issuperset', 'pop', 'remove', 'symmetric_difference', 'symmetric_difference_update', 'union', 'update']
    
    • 只要是能被for循环的数据类型,就一定拥有 __iter__ 方法
    • __iter__ 方法做了什么事情呢?
    print([].__iter__())
    
    # 结果呈现
    <list_iterator object at 0x0000001BFD34A470>
    
    • 执行了 list([])__iter__ 方法,好像得到了一个 ````list_iterator```,现在我们又得到了一个新名词—— iterator

    • iterator,这里给我们标出来了,是一个计算机中的专属名词,叫做 迭代器

    • 总结:可以被for循环的都是可迭代的,要想可迭代,内部必须有一个 __iter__ 方法。

    1.2.2 迭代器协议

    • 现在已经有一个迭代器了,这个迭代器是一个列表的迭代器。

    • 使用 set 集合 ,取 list str dic range 双下方法 的交集

    ret = set(dir([]))&set(dir(""))&set(dir({}))&set(dir(range(10)))
    print(ret)      # iterable
    
    # 结果呈现
    {'__lt__', '__init__', '__le__', '__hash__', '__reduce__', '__format__', '__init_subclass__', '__delattr__', '__ne__', '__setattr__', '__class__', '__ge__', '__new__', '__iter__', '__dir__', '__str__', '__repr__', '__eq__', '__subclasshook__', '__reduce_ex__', '__len__', '__doc__', '__getattribute__', '__getitem__', '__gt__', '__sizeof__', '__contains__'}
    
    • 一个列表执行了 __iter__() 之后就是迭代器
    print(dir([]))
    
    # 结果呈现
    ['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
    
    • 使用set 集合 ,取 iter 和 list 的差集
    '''
    dir([1,2].__iter__())是列表迭代器中实现的所有方法,dir([1,2])是列表中实现的所有方法,都是以列表的形式返回给我们的,为了看的更清楚,我们分别把他们转换成集合,
    然后取差集。
    '''
    print(dir([1,2].__iter__()))
    print(dir([1,2]))
    print(set(dir([1,2].__iter__()))-set(dir([1,2])))
    
    # 结果呈现
    ['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__length_hint__', '__lt__', '__ne__', '__new__', '__next__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setstate__', '__sizeof__', '__str__', '__subclasshook__']
    ['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
    {'__setstate__', '__next__', '__length_hint__'}                
    
    • 在列表迭代器中有三个方法,那么这三个方法都分别做了什么事呢?
    # print([1, "a", "kkk"].__iter__().__length_hint__())     # 元素个数 3
    iter_l = [1,2,3,4,5,6].__iter__()
    # 获取迭代器中元素的长度
    print(iter_l.__length_hint__())
    # 根据索引值指定从哪里开始迭代
    print('*',iter_l.__setstate__(4))
    # 一个一个的取值
    print('**',iter_l.__next__())
    print('***',iter_l.__next__())
    
    
    # 结果呈现
    6
    * None
    ** 5
    *** 6
    
    • 能让我们一个一个取值的神奇方法是 __next__()
    • 在for循环中,就是在内部调用了__next__方法才能取到一个一个的值
    • 验证 __next__()
    lis = [1, 2, 3]
    print(lis.__iter__().__next__())
    print(lis.__iter__().__next__())
    print(lis.__iter__().__next__())
    iterator = lis.__iter__()
    print(iterator.__next__())
    print(iterator.__next__())
    print(iterator.__next__())
    
    # 结果呈现
    1
    1
    1
    1
    2
    3
    
    • 如果我们一直取next取到迭代器里已经没有元素了,就会抛出一个异常StopIteration,告诉我们,列表中已经没有有效的元素了。
    lis = [1, 2, 3]
    iterator = lis.__iter__()
    print(iterator.__next__())
    print(iterator.__next__())
    print(iterator.__next__())
    print(iterator.__next__())
    
    # 结果呈现
    1
    Traceback (most recent call last):
    2
      File "C:/Users/thinkpad/Envs/daily_test/test_project/test_file.py", line 6, in <module>
    3
        print(iterator.__next__())
    StopIteration
    
    • 这个时候,我们就要使用异常处理机制来把这个异常处理掉。
    lis = [1, 2, 3]
    iterator = lis.__iter__()
    while True:
        try:
            item = iterator.__next__()
            print(item)
        except StopIteration:
            break
    
    # 结果呈现
    1
    2
    3
    
    • 使用while循环实现了原本for循环做的事情,从 iterator 那儿获取一个一个的值,这个 iterator 就是一个迭代器。

    • 迭代器遵循迭代器协议:必须拥有 __iter__ 方法和 __next__ 方法。

    • Iterable 可迭代 - - 》 __iter__ # 只要含有 __iter__ 方法的都是可迭代的,都可以被 for 循环

    • [].__iter__() 迭代器 - - 》 __next__ # 通过 __next__ 方法就可以从迭代器中一个个的取值

    • 只要含有 __iter__ 方法的都是可迭代的 - - 可迭代协议

    • 迭代器协议 - - 》 内部含有 __next____iter__ 方法的就是 迭代器

    print("__iter__" in dir([].__iter__()))
    print("__next__" in dir([].__iter__()))
    
    # 结果呈现
    True
    True
    
    from collections import Iterable
    from collections import Iterator
    print(isinstance([],Iterator))
    print(isinstance([],Iterable))
    
    class A:
        def __iter__(self):pass
        def __next__(self):pass
    
    a = A()
    print(isinstance(a,Iterator))
    print(isinstance(a,Iterable))
    
    l = [1, 2, 3, 4]
    for i in l.__iter__():
        print(i)
    
    # 结果呈现
    False
    True
    True
    True
    1
    2
    3
    4
    
    • 还账:next和iter方法

    • 如此一来,关于迭代器和生成器的方法我们就还清了两个,最后我们来看看range()是个啥。首先,它肯定是一个可迭代的对象,但是它是否是一个迭代器?我们来测试一下

    print('__next__' in dir(range(12)))  #查看'__next__'是不是在range()方法执行之后内部是否有__next__
    print('__iter__' in dir(range(12)))  #查看'__next__'是不是在range()方法执行之后内部是否有__next__
    
    from collections import Iterator
    print(isinstance(range(100000000),Iterator))  #验证range执行之后得到的结果不是一个迭代器
    
    # 结果呈现
    False
    True
    False
    

    1.3 为什么要有for循环

    for循环 就是基于迭代器协议提供了一个统一的可以遍历所有对象的方法,即在遍历之前,先调用对象的 __iter__ 方法将其转换成一个迭代器,然后使用迭代器协议去实现循环访问,这样所有的对象就都可以通过for循环来遍历了,而且你看到的效果也确实如此,这就是无所不能的 for循环

    l=[1,2,3]
    
    index=0
    while index < len(l):
        print(l[index])
        index+=1
    
    # 结果呈现
    1
    2
    3
    

    1.4 斐波那契数列

    class Fibonacci(object):
        def __init__(self, all_num):
            self.all_num = all_num
            self.current_num = 0
            self.a = 0
            self.b = 1
    
        def __iter__(self):
            return self
    
        def __next__(self):
            if self.current_num < self.all_num:
                ret = self.a
    
                self.a, self.b = self.b, self.a + self.b
                self.current_num += 1
                return ret
            else:
                raise StopIteration
    
    fibo = Fibonacci(10)
    
    for num in fibo:
        print(num)
    

    2,生成器

    2.1 初识生成器

    • 迭代器有两种:一种是调用方法直接返回的,一种是可迭代对象通过执行 __iter__ 方法得到的,迭代器有的好处是可以节省内存。

    • 如果在某些情况下,我们也需要节省内存,就只能自己写。我们自己写的这个能实现迭代器功能的东西就叫生成器。

    • Python中提供的生成器:

      • 1.生成器函数:常规函数定义,但是,使用 yield 语句而不是 return 语句返回结果。yield 语句一次返回一个结果,在每个结果中间,挂起函数的状态,以便下次重它离开的地方继续执行
      • 2.生成器表达式:类似于列表推导,但是,生成器返回按需产生结果的一个对象,而不是一次构建一个结果列表
    • 生成器Generator:

      • 本质:迭代器(所以自带了 __iter__ 方法和 __next__ 方法,不需要我们去实现)
      • 特点:惰性运算,开发者自定义

    2.2 生成器函数

    • 一个包含 yield 关键字的函数就是一个生成器函数。
    • yield 可以为我们从函数中返回值,但是 yield 又不同于 returnreturn 的执行意味着程序的结束,调用生成器函数不会得到返回的具体的值,而是得到一个可迭代的对象。每一次获取这个可迭代对象的值,就能推动函数的执行,获取新的返回值。直到函数执行结束。
    • 生成器的好处:就是不会一下子在内存中生成太多数据

    2.2.1 初识生成器

    def generator():
        print(1)
        yield "a"
        print(2)
        yield "b"
        yield "c"
    
    # 生成器函数:执行之后会得到一个生成器作为一个返回值
    result = generator()
    print(result)        # #打印result可以发现result就是一个生成器
    
    print(result.__next__())
    print(result.__next__())
    print(result.__next__())
    # 等同于以上几个print
    # for i in result:
    #     print(i)
    
    # 结果呈现
    <generator object generator at 0x0000007D40697C78>
    1
    a
    2
    b
    c
    

    2.2.2 生成器表达式例子

    def generator():
        for i in range(20):
            yield "娃哈哈 %s" % i
    
    g = generator()     # 调用生成器函数得到一个生成器
    ret = g.__next__()        # 每一次执行 g.__next__()  就是从生成器中取值,预示着生成器函数中的代码继续执行
    print("#*# %s" % ret)
    num = 0
    for i in g:
        num += 1
        if num > 10:
            break
        print(i)
    
    print(list(g))        # 提取完后,剩余的值
    
    # 结果呈现
    #*# 娃哈哈 0
    娃哈哈 1
    娃哈哈 2
    娃哈哈 3
    娃哈哈 4
    娃哈哈 5
    娃哈哈 6
    娃哈哈 7
    娃哈哈 8
    娃哈哈 9
    娃哈哈 10
    ['娃哈哈 12', '娃哈哈 13', '娃哈哈 14', '娃哈哈 15', '娃哈哈 16', '娃哈哈 17', '娃哈哈 18', '娃哈哈 19']
    
    

    2.2.3 监听文件输入的例子

    generator_file 文件内容

    sadf
    qwer2415
    avxv1245qgarg
    sdf
    sdfa
    asdfafdaf
    
    j89796960ok
    aq24515af
    12324151515
    a123
    sadf
    python
    
    def tail(filename):
        f = open(filename,encoding="utf-8")
        while True:
            line = f.readline()
            if line.strip():
                yield line.strip()
    
    g = tail("generator_file")
    for i in g:
        if "python" in i :
            print("***", i)
    
    # 结果呈现
    *** python
    
    • 从生成器中取值的几个方法
      • next
      • for
      • 数据类型的强制转换 ,但是占内存,不推荐

    2.2.4 生成器函数进阶 - - send

    
    def generator():
        print(123)
        num = yield 1
        print("=====",num)
        print(456)
        yield 2
        print(789)
    
    g = generator()
    ret = g.__next__()
    print("***", ret)
    ret = g.send("Hello")      # send 的效果和 next 一样
    print("***", ret)
    
    # 结果呈现
    123
    *** 1
    ===== Hello
    456
    *** 2
    
    • send 获取下一个值的效果和 next 基本一致
    • 只是在获取下一个值的时候,给上一值的位置传递一个数据
    • 使用 send 的注意事项
      • 第一次使用生成器的时候 是用的 next 获取下一个值
      • 最后一个 yield 不能接受外部的值

    2.2.5 获取移动平均值

    # avg = sum/count
    def average():
        sum = 0
        count = 0
        avg = 0
        while True:
            num = yield avg
            sum += num      # 10
            count += 1      # 1
            avg = sum/count
    
    
    avg_g = average()
    avg_g.__next__()
    avg1 = avg_g.send(10)
    avg2 = avg_g.send(50)
    print(avg2)
    
    # 结果呈现
    30.0
    

    2.2.6 预激生成器的装饰器

    def init(func):     # 装饰器
        def inner(*args, **kwargs):
            g = func(*args, **kwargs)   # g = average()
            g.__next__()
            return g
        return inner
    
    @init
    def average():
        sum = 0
        count = 0
        avg = 0
        while True:
            num = yield avg
            sum += num      # 10
            count += 1      # 1
            avg = sum/count
    
    avg_g = average()
    ret = avg_g.send(10)
    print(ret)
    ret = avg_g.send(20)
    print(ret)
    
    # 结果呈现
    10.0
    15.0
    

    2.2.7 yield from

    def generator():
        a = 'abcde'
        b = '12345'
        for i in a:
            yield i
        for i in b:
            yield  i
    
    g = generator()
    for i in g:
        print(i)
    
    # 结果呈现
    a
    b
    c
    d
    e
    1
    2
    3
    4
    5
    
    def generator():
        a = 'abcde'
        b = '12345'
        yield from a
        yield from b
    g = generator()
    for i in g:
        print(i)
    
    # 结果呈现
    a
    b
    c
    d
    e
    1
    2
    3
    4
    5
    

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

    3.1 列表推导式

    egg_list = []
    for i in range(10):
        egg_list.append("鸡蛋 %s" % i )
    
    egg_list = ["鸡蛋 %s" % i for i in range(10)]       # 列表推导式
    print(egg_list)
    
    print([i for i in range(10)])
    print([i * i for i in range(10)])
    
    # 结果呈现
    ['鸡蛋 0', '鸡蛋 1', '鸡蛋 2', '鸡蛋 3', '鸡蛋 4', '鸡蛋 5', '鸡蛋 6', '鸡蛋 7', '鸡蛋 8', '鸡蛋 9']
    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
    

    3.2 生成器表达式

    g = (i for i in range(10))
    print(g)
    for i in g:
        print(i)
    
    # 结果呈现
    <generator object <genexpr> at 0x00000065EE0D7C78>
    0
    1
    2
    3
    4
    5
    6
    7
    8
    9
    

    3.3 生成器表达式 区别于 列表推导式

    • 括号不一样
    • 返回的值不一样 = = 几乎不占用内存
    egg_list = ("鸡蛋 %s" % i for i in range(10))       # 生成器
    print(egg_list)
    for i in egg_list:
        print(i)
    
    g = (i*i for i in range(10))
    g.__next__()
    for i in g:
        print(i)
    
    # 结果呈现
    <generator object <genexpr> at 0x000000C74DB47C78>
    鸡蛋 0
    鸡蛋 1
    鸡蛋 2
    鸡蛋 3
    鸡蛋 4
    鸡蛋 5
    鸡蛋 6
    鸡蛋 7
    鸡蛋 8
    鸡蛋 9
    1
    4
    9
    16
    25
    36
    49
    64
    81
    
    • 总结
      • 1.把列表解析的[]换成()得到的就是生成器表达式
      • 2.列表解析与生成器表达式都是一种便利的编程方式,只不过生成器表达式更节省内存
      • 3.Python不但使用迭代器协议,让for循环变得更加通用。大部分内置函数,也是使用迭代器协议访问对象的。例如, sum函数是Python的内置函数,该函数使用迭代器协议访问对象,而生成器实现了迭代器协议,所以,我们可以直接这样计算一系列值的和:
    sum(x ** 2 for x in range(4))
    
    • 而不用多此一举的先构造一个列表:
    sum([x ** 2 for x in range(4)]) 
    

    4,本章小结

    • 迭代器

      • 可迭代协议 - - 含有 iter 方法的都是可迭代的 ("__iter__" in dir (数据))
        • 可迭代的一定可以被 for循环
        • 例如:range(),str,list,tuple,dict,set
      • 迭代器协议 - - 含有 nextiter 的都是迭代器
        • 迭代器一定可迭代,可迭代的通过调用 __iter()__ 方法就能得到一个迭代器
        • 例如: iter(range()),iter(str),iter(list),iter(tuple),iter(dict),iter(set),reversed(list_o),map(func,list_o),filter(func,list_o),file_o
      • 特点;
        • 方便逐个取值,一个迭代器只能取一次
        • 节省空间
    • 生成器函数Generator

      • 本质:迭代器,所以拥有 __iter__ 方法和 __next__ 方法
      • 特点:惰性运算,开发者自定义
      • 含有 yield 关键字的函数都是生成器函数
      • 生成器函数的特点
        • 调用之后函数内的代码不执行,返回生成器
        • 每次调用 next 方法的时候会取到一个值
        • 每从生成器中取一个值就会执行一段代码,遇到yield就停止
      • 如何从生成其中取值:
        • for :如果没有break会一直取到去完为止
        • next :每次只取一个
        • send :不能用在第一个,取下一个值的时候给上个位置传新的值
        • 数据类型强制转换 :会一次性把所有数据都读取到内存里
    • 生成器表达式
      - (条件成立想放在生成器中的值 for i in 可迭代的 if 条件)

    • 使用生成器的优点:

      • 1.延迟计算,一次返回一个结果。也就是说,它不会一次生成所有的结果,这对于大数据量处理,将会非常有用。
      • 2.提高代码可读性
    #列表解析
    sum([i for i in range(100000000)])#内存占用大,机器容易卡死
     
    #生成器表达式
    sum(i for i in range(100000000))#几乎不占内存
    

    5,生成器相关的面试题

    5.1 处理文件,用户指定要查找的文件和内容,将文件中包含要查找内容的每一行都输出到屏幕

    # test_file.txt 文件内容
    sadf
    qwer2415
    avxv1245qgarg
    sdf
    sdfa
    asdfafdaf
    j89796960ok
    aq24515af
    12324151515
    a123
    sadf
    python
    2f4qt4ypython
    
    def check_file(filename, aim):
        with open(filename, encoding="utf-8") as f:   # 句柄:handler
            for i in f:
                if aim in i:
                    yield i
    
    g = check_file("test_file.txt","python")
    for i in g:
        print(i.strip())
    
    # 结果呈现
    python
    2f4qt4ypython
    

    5.2写生成器,从文件中读取内容,在每一次读取得到的内容之前加上 “***” 之后返回给用户

    def check_file(filename):
        with open(filename, encoding="utf-8") as f:   # 句柄:handler
            for i in f:
                yield "***" + i
    for i in check_file("test_file.txt"):
        print(i.strip())
    
    # 结果呈现
    ***sadf
    ***qwer2415
    ***avxv1245qgarg
    ***sdf
    ***sdfa
    ***asdfafdaf
    ***j89796960ok
    ***aq24515af
    ***12324151515
    ***a123
    ***sadf
    ***python
    ***2f4qt4ypython
    

    5.3 求 g1 g2 的值各是什么?

    def demo():
        for i in range(4):
            yield i
    
    g = demo()
    
    g1 = (i for i in g)
    g2 = (i for i in g1)
    
    print(list(g1))
    print(list(g2))
    
    # 结果呈现
    [0, 1, 2, 3]
    []
    

    5.4 求 g 的值是什么?

    def add(n, i):
        return n + i
    
    def test():
        for i in range(4):
            yield i
    
    g = test()
    
    for n in [1, 10]:
        g = (add(n, i) for i in g)
    
    # 结果呈现
    [20, 21, 22, 23]
    

    5.5 tail & grep

    import os
    
    def init(func):
        def wrapper(*args,**kwargs):
            g=func(*args,**kwargs)
            next(g)
            return g
        return wrapper
    
    @init
    def list_files(target):
        while 1:
            dir_to_search=yield
            for top_dir,dir,files in os.walk(dir_to_search):
                for file in files:
                    target.send(os.path.join(top_dir,file))
    @init
    def opener(target):
        while 1:
            file=yield
            fn=open(file)
            target.send((file,fn))
    @init
    def cat(target):
        while 1:
            file,fn=yield
            for line in fn:
                target.send((file,line))
    
    @init
    def grep(pattern,target):
        while 1:
            file,line=yield
            if pattern in line:
                target.send(file)
    @init
    def printer():
        while 1:
            file=yield
            if file:
                print(file)
    
    g=list_files(opener(cat(grep('python',printer()))))
    
    g.send('/test1')
    
    # 协程应用:grep -rl /dir
    
  • 相关阅读:
    Java安全之JNDI注入
    Visual Studio 2019 升级16.8之后(升级.Net 5),RazorTagHelper任务意外失败
    .Net Core 3.1升级 .Net 5后出现代码错误 rzc generate exited with code 1.
    重走py 之路 ——普通操作与函数(三)
    重走py 之路 ——字典和集合(二)
    设计模式结(完结篇)
    重走py 之路 ——列表(一)
    RestfulApi 学习笔记——分页和排序(五)
    RestfulApi 学习笔记——查询与过滤还有搜索(五)
    Android开发 Error:The number of method references in a .dex file cannot exceed 64K.Android开发 Error:The number of method references in a .dex file cannot exceed 64K
  • 原文地址:https://www.cnblogs.com/xiaoqshuo/p/9669997.html
Copyright © 2011-2022 走看看