zoukankan      html  css  js  c++  java
  • 第十三天

    第一部分 迭代器

    """
    迭代器
    """
    li=[1,2,3,4]
    tu=(1,2,3,4)
    s="abc"
    b=b"def"
    d={"a":1,"b":2}
    se={1,2,3}
    for i in li:
        pass
    for i in tu:
        pass
    for i in s:
        pass
    for i in b:
        pass
    for i in d:
        pass
    for i in se:
        pass
    # for i in 1:
    #     pass
    

      


    1. 可迭代对象
    # 能够放在for循环中进行遍历的类型,就是可迭代类型,产生的对象就是可迭代对象
    # 可迭代对象类型,在python collections.abc.Iterable,包括__iter__方法。所有的可迭代对象。
    # 必须都实现__iter__方法。返回的是迭代器。
    # 学过的list,tuple等可迭代对象都是继承了这个父类Iterable,实现__iter__

    from collections.abc import Iterable
    print(issubclass(list,Iterable))
    print(issubclass(tuple,Iterable))
    print(issubclass(str,Iterable))
    print(issubclass(bytes,Iterable))
    print(issubclass(dict,Iterable))
    print(issubclass(set,Iterable))
    print(issubclass(int,Iterable))
    

      

    # 说明:可迭代对象有一些没有实现__iter__方法,是特殊的,而是实现的__getiterm__方法

    2. 迭代器
    # 迭代器是迭代对象的特殊类型,迭代器是迭代对象的子类
    from collections.abc import Iterator
    print(issubclass(Iterator,Iterable))

    # 在迭代器中两个重要方法 __next__ __iter__
    # __next__方法:能够返回迭代器下一个元素
    li=[1,2,3] # li是迭代对象
    # __iter__方法:能够返回迭代器
    # li.__iter__() iter(li)在调用上等价,但是建议用后一种方法
    # it=iter(li)
    # it 是迭代器,迭代器中包含了所有的元素
    it=iter(li)
    # it.__next__() next(it)在调用上等价,建议用后一种
    print(it.__next__())
    print(next(it))
    print(next(it))
    print(next(it)) # 当迭代器中的元素已经全部被next获得之后,会报StopIteration的异常
    # 迭代器产生一次,只要遍历过,当前的迭代器中的元素就没有了。

    # for 循环是怎么做到可以一直遍历迭代对象的呢?
    # 是因为每次for的时候,都会新创建一个迭代器,进行迭代
    li1=[1,2,3,4,5]
    # it=li1.__iter__()
    # 获得当前迭代对象的迭代器(这个迭代器一次只产生一个)
    it=iter(li1)
    while True:
    try:
    item=next(it)
    except StopIteration:
    del it
    break
    # 注意:
    # 1. 分清迭代对象是什么?迭代器是什么?
    # Iterable 迭代对象,我们学过的所有的list,tuple都是Iterable的子类
    # 如果新创建一个列表,是一个对象,是list的对象,list是Iterable的子类

    # 2. 他们之间的关系
    # Iterator,是迭代对象的子类

    # 3. 迭代对象下有什么方法?干什么的?
    # # Iterable下有__iter__方法,注意,调用的时候,可以直接使用__iter__,建议使用iter(迭代对象)
    # iter 方法能够返回一个迭代器。

    # 4. 迭代器下有什么方法?干什么的?
    # Iterator 有__next__:能够找到迭代器中的下一个对象。
    # 还有 __iter__:return self。 为了扩展使用

    # 注意,迭代器在遍历一次之后,迭代器的元素就没了,如果需要再次遍历,需要重新使用迭代对象
    # 调用迭代对象下的iter方法创建新的迭代器。

    3. 自定义迭代对象和迭代器。
    # 符合如下规则:
    迭代对象: 里面实现__iter__方法。
    迭代器: 里面实现__iter__和__next__方法
    class MyIterable:
    def __iter__(self):
    pass
    class MyIterator:
    def __iter__(self):
    pass
    def __next__(self):
    pass
    # 只要定义的迭代对象,实现了__iter__方法,那么它就是迭代对象,就是Iterable的子类,不需要显示继承
    # 只要定义了迭代器,实现了__next__ 和__iter__,那么它就是迭代器,就是iterator的子类,不需要显示继承

    m=MyIterable()
    print(isinstance(m,Iterable))
    print(issubclass(MyIterable,Iterable))
    n=MyIterator
    print(isinstance(n,Iterator))
    print(issubclass(MyIterator,Iterator))
    
    class MyIterable1:
        def __iter__(self):
            self.li=[1,2,3,"a"]
            return
    class MyIterator1:
        def __init__(self,li):
            self.li=li
            self.index=0
        def __iter__(self):
            pass
        def __next__(self):
            if self.index<len(self.li):
                s=self.li[self.index]
                self.index+=1
                return s
            else:
                # 当索引大于长度
                raise StopIteration
    m=MyIterable()
    m1=iter(m)
    print(m1.__next__())
    print(next(m1))
    

      


    # 为什么list 或者tuple这些可迭代的数据类型被设计成“迭代对象”,而不是直接设计成“迭代器"?
    # 迭代器


    # 写一个迭代器,实现一个倒数的迭代器



    4. 迭代器的缺点
    # (1) 必须要去实现iter方法和next方法
    # (2) 如果不是用for 循环,那么无返回值的时候,需要捕捉StpIteration的异常
    # (3) 一次性全部迭代,结果未必是一下子全部使用,当数量级太大的时候,会占用太多的内存

    # 解决方法-------生成器


    第二部分 生成器

    """
    生成器
    在python2.5之后出现的,生成器返回一个可迭代的对象,但是不是立即返回所有的值,而是一个一个的生成值
    懒加载:延迟加载,按需加载。
    生成器,其实就是给一个函数,生成一个懒加载的迭代器。
    """
    # 将列表中的每一个元素的数,求平方
    li=[]
    for i in range(1,101):
    li.append(i**2)
    print(li)

    print([i**2 for i in range(1,101)])

    # 生成器的实现有两种方式:一种生成器表达式,另一种是生成器函数
    1. 使用生成器表达式
    linew=(i**2 for i in range(1,101))
    # linew是一个生成器对象
    print(linew)
    # 因为生成器底层是迭代器,使用for 循环,可以触发生成器产生每一个元素
    # for i in linew:
    # print(i)
    # 生成器就是迭代器,遍历完一次之后就没有东西了
    print(next(linew))

    2. 生成器函数
    生成器函数就看有没有yield
    # 定义一个普通函数
    # def f():
    # for i in range(1,101):
    # print(i)
    # f()

    # 生成器函数
    def f():
    print("生成器函数开始执行")
    for i in range(1,101):
    yield i
    print(i,"暂停之后继续执行")
    a=f()
    print(a)
    a.__next__()
    next(a)
    next(a)
    for i in a:
    print(i)

    # 练习:使用正常函数和生成器函数写出斐波那契数列
    def f():
    print("程序开始执行")
    a=0
    b=1
    for i in range(100):
    print("yield之前")
    yield b
    print("yield之后继续执行")
    a,b=b,a+b
    g=f()
    print(next(g))
    print(next(g))
    print(next(g))
    print(next(g))

    # 说明: 1. 生成器函数,在被调用的时候,只会产生一个生成器对象(本质迭代器对象)
    # 2. 不会运行函数中的任何一行代码
    # 3. 当使用next(生成器对象),才触发函数执行,运行到yield暂停
    # 4. 当继续调用next函数时,从刚才暂停的位置,继续向后执行

    """
    生成器函数和普通函数的区别
    1. 生成器函数会包含一个或者多个yield
    2. 当生成器函数运行到yield,暂停,相当于把控制权交给调用者
    """

    3. yield表达式。
    # 在生成器函数除了可以使用yield产生一个值以外,其实,同时yield表达式本身还具有一个值,
    # 不是产出的值,而是使用send方法传递进去的值
    # send(值)
    def fun():
    for i in range(100):
    value=yield i
    print(value)
    g=f()
    print(g.send(None))
    print(g.send("send传入的值"))
    print(next(g))
    print(g.send("这是send传进来的值"))
    print(g.send(None))

    # send 和 next 他们都可以调用生成器对象产生的元素
    # 调用next函数,相当于传入值None,next函数的返回值是yield生成的内容
    # 调用send函数,可以传入yield表达式的值(生成器函数中value值,value=yield i)
    # send函数的返回值,也是yield生成的内容
    # 第一次调用next唤醒生成器对象,跟使用send(None)效果一样
    # 第一次调用只能使用send(None),分析原因,停在yield,还没有对左侧的value进行赋值

    # 需求:使用生成器产生一系列的值,比如,1,2,3..到5时,返回给客户端,说太大了,变小点
    # 生成器在继续产生4,3,2,1,到1的时候,客户端说太小了,变大点,生成器继续产生2,3,4,5
    第三部分 闭包
    """
    闭包:
    在内部函数中,访问外部函数的变量,在外部函数中,直接返回内部函数引发调用
    (1) 有嵌套函数
    (2) 内部函数可以访问到外部函数的变量
    (3) 外部函数返回内部函数的名字
    """
    def abc():
        print("已经存在的函数")
    def outer(a):
        x=1
        def inner():
            print(x)
            print(a)
            print("inner函数")
        return inner
    
    inner=outer("abc")
    print(inner.__closure__)
    inner()
    

      

    # 闭包的作用:
    # 1. 当函数执行结束时,内部函数依然可以引用到外部函数中定义的变量,下一次再调用内部函数时
    # 依然可以调用到外部函数中变量值。
    # 2. 内部函数的名称处于局部命名空间,不会对外部全局命名空间造成影响,即使函数名相同也没问题

    # 实现bill第几天上班
    def on_duty(name):
        times=0
        times+=1
        print("这是{}第{}次上班".format(name,times))
    on_duty("bill")
    on_duty("bill")
    
    # 闭包
    def on_duty(name):
        times=0
        def inner():
            nonlocal times
            times+=1
            print("这是{}第{}次上班".format(name,times))
        return inner
    
    duty=on_duty("bill")
    duty()
    duty()
    duty()
    

     

    # 通过类也能实现闭包
    class Onduty:
        def __init__(self,name):
            self.name=name
            self.times=0
        def __call__(self, *args, **kwargs):
            self.times+=1
            print("这是{}第{}次上班".format(self.name,self.times))
    duty=Onduty("bill")
    duty()
    duty()
    

      





















  • 相关阅读:
    25 BasicUsageEnvironment0基本使用环境基类——Live555源码阅读(三)UsageEnvironment
    26 BasicUsageEnvironment基本使用环境——Live555源码阅读(三)UsageEnvironment
    24 UsageEnvironment使用环境抽象基类——Live555源码阅读(三)UsageEnvironment
    23 使用环境 UsageEnvironment——Live555源码阅读
    关于linux中文乱码的问题。
    关于ubuntukylin安装后界面中英文混杂的问题
    网络数据包发送工具PacketSender中文源码
    21 BasicTaskScheduler基本任务调度器(一)——Live555源码阅读(一)任务调度相关类
    20 BasicTaskScheduler0 基本任务调度类基类(二)——Live555源码阅读(一)任务调度相关类
    19 BasicTaskScheduler0 基本任务调度类基类(一)——Live555源码阅读(一)任务调度相关类
  • 原文地址:https://www.cnblogs.com/ztx695911088/p/9108961.html
Copyright © 2011-2022 走看看