zoukankan      html  css  js  c++  java
  • Python之 反射、迭代器、生成器

    一、反射

    反射就是通过 内置函数getattr() 以字符串的形式导入模块以字符串的形式调用模块/对象里方法

    l=['add','del','set','find']
    for i in l:
        print(i)
    choice=input("请输入您需要的操作:".strip())
    mode=__import__(choice)    #相当于 import 模块
    getattr(mode,choice[0])()  #获取  模块里定义的方法(函数)并且执行;

    二、迭代器

    Python的数据类型分为

    不可迭代类型(数字、布尔值)

    可迭代类型(字符串、列表、元组、集合、字典、文件句柄、range、枚举....),

    这些可迭代对象有一个共同的特征就是可以被for循环,而不能被for循环的都是不可迭代对象;

    那么他们为什么可以被for循环呢?

    Python种一切皆对象体现在+/-....语法都可以被Python解释隐藏调用一些双下(__add__。。。。)方法也就是已经被C语言实现好了的方法,当解释器遇到语法就会调用其对应的双下方法,进而返回结果;

    顺腾摸瓜我们就来看一下这些可迭代对象中都隐藏了什么__共同的双下___方法;

    ret=set(dir({})) & set(dir([])) & set(dir(()))
    print(ret)
    
    {
    '__reduce__', '__eq__', '__reduce_ex__', '__getitem__', '__len__', '__sizeof__', '__getattribute__',

    '__format__', '__subclasshook__', '__delattr__', '__gt__', '__setattr__', '__hash__', '__contains__',

    '__class__', '__iter__', '__doc__', '__le__', '__new__', '__init_subclass__', '__repr__', '__ge__',

    '__lt__', '__ne__', '__dir__', '__str__', '__init__'

    }
    print('__iter__' in set(dir({})))      #可迭代对象拥有__iter__双下方法
    print('__iter__' in set(dir(True)))   #不可迭代对象没有__iter__双下方法

    得知所有的可迭代对象内部都有1个__inter__()双下方法,这就是Python中规定的可迭代协议

    所以在for循环执行之前会去寻找循环对象的__inter__方法,如果没有__inter__方法,循环会直接报错,这是不可以迭代的对象;

    l1=[1,2,3,4]
    print(l1.__iter__())

     所有可迭代对象执行__iter__双下方法之后都会返回1个迭代器

    l1=[1,2,3,4]
    print(set(dir(l1.__iter__())) - set(dir({})))
    
    #{'__setstate__', '__next__', '__length_hint__'}

    迭代器可迭代对象多了3个双下方法分别是:__setstate__, __next__, __length_hint__

    class A():
        def __iter__():pass
        def __next__():pass
    
    a=A()    
    
    from collections import Iterable     
    from collections import Iterator        
    
    print(isinstance(a,Iterable))#可迭代对象
    print(isinstance(a,Iterator))#迭代器

    迭代器协议:实现了__iter__ + __next__方法就是一个迭代器;

     迭代器的作用:

    1.由于可迭代对象生成数据是不会一下生成全部的数据,而是生成一个迭代器,然后1个1个得吐给你,所以就避免可生成大数据导致内存撑爆;

    generater=range(10000000000000000000000000)        #迭代器把数字1个1个得吐出来,不会占用1大块内存,而是随着for循环/__next__()1个1个得生成;
    for n in generater: #随着for循环1个1个得取处迭代器中值
        print(n)
    
    #big_data=list(range(10000000000000000000000000)) #会把数据1次生成,如果数据量过大,容易沾满内存

    2.for循环是 对可迭代协议的实现

    为啥列表/字典这些可迭代对象,没有__next__方法,容器中的元素也可以被 for循环出来呢?

    因为for循环先执行了 [].__iter()__()把可迭代对象中__iter__()方法returen的结果组成 1个迭代器

    然后1次1次得执行 [].__iter()__()__next__()把元素1个1个得获取出来。

    #Python中for 循环的原理
    list1=['1','2','3','4','5']
    g=list1.__iter__()  #第1步:可迭代对象执行__iter__()得到1个生成器g
    print(g.__next__()) #第2步:生成器g.__next__()遍历数据
    print(g.__next__())
    print(g.__next__())
    print(g.__next__())

    迭代器的应用场景

    在平时写代码的过程中,需要产生大量的数据,但1次性全部生成又会导致内存占用量大,就可以使用迭代器协议,先生成迭代器,然后1个1个得吐出数据;

    三、生成器

    生成器的本质还是迭代器,可不过这个迭代器是程序员自己实现的

    实现生成器有2种方式:

    方式1:yield写生成器函数

    def func():                #普通函数
        return 'zhanggen'
    
    ret=func()
    print(ret)
    ------------------------------------------------------------------
    def generator():      #0.生成器函数:函数内部包含yield关键字,就是生成器函数
        yield 'zhang'
        yield 'gen'
    
    g= generator()        #1.生成器函数被调用后,得到1个生成器也就是迭代器作为返回值。
    print(g.__next__())   #2.使用__next__()从里面取值
    print(g.__next__())

    使用生成器生成1000000个哇哈哈哈,只获取前50个

    def wahaha():
        for i in range(1000000):
            yield "wahaha%s" %i
            
            
    g=wahaha()
    print (g.__next__())#wahaha0
    
    count=0            #获取前50个
    for i in g:
        count+=1
        if count<=50:
            print('for循环....%s'%i)

     监听文件的输入,然后过滤用户输入的关键字

     

    方式2:生成器表达式

    g=(i for i in range(1,100))
    
    print(g.__next__())

     四、生成器进阶

    send语法

    send的作用和next类似,不同的是send可以在获取生成器函数里面 下1个yield 值的同时,还可以在上1个yield 值的右边send1个值到生成器函数里面。

    def generator():
        print(123)
        num=yield 1  #Python解释器当遇到1个等号时 先执行右边的yield 1,然后赋值num=yield 1
        print('send传入的值',num)
        print(456)
        num1=yield 2
        print(num1)
        yield 3
    g=generator()
    print(g.__next__())   #第一次调用生成器时不能使用 send
    print(g.send('hello'))#send的效果和__next__效果一样
    print(g.send('hello1'))#send的效果和__next__效果一样
    print(g.__next__())#最后1次调用生成器不使用 send

    使用send的注意事项:

    综上所述send的功能,send不可以 第1次和最后1次调用生成器时使用。

    如何让1个生成器,无限的yield值 ,不会遇到  StopIteration异常。

    def average():
        print('start')
        num=0
        while True:#下次调用 __next__依然在while循环里面
            num+=4
            yield num #4 8 12 16... 
    
    
    g=average()
    
    print(g.__next__())
    print(g.__next__())
    print(g.__next__())
    print(g.__next__())
    print(g.__next__())
    print(g.__next__())

    使用sen不断求平均值

    #不断得计算平均值
    def average():
        sum_=0
        count_=0
        avg_=0
        while True:
            num_=yield avg_
            sum_+=num_
            count_+=1
            print(sum_,num_,count_)
            avg_=sum_/count_
    
    avg_g=average()
    avg_g.__next__()
    print(avg_g.send(10))
    print(avg_g.send(12))
    print(avg_g.send(15))
    print(avg_g.send(16))

     yield from 语法

    yield from 帮助我们从序列数据类型里1个1个得yield 出每1个元素,而不是使用 for 循环

    def generator():
        a='abcde'
        b='12345'
        yield  a
        yield b
    '''
    abcde
    12345
    '''
    g=generator()
    for i in g:
        print(i)
    
    def generator():
        a='abcde'
        b='12345'
        yield from a  #帮助我们从序列数据类型里,1个1个yield 出每个元素,而不是使用 for 循环。
        yield from b
    
    g=generator()
    for i in g:
        print(i)
    
    '''
    a
    b
    c
    d
    e
    1
    2
    3
    4
    5
    
    '''

    chain多个生成器

    def coroutine1(n):
        print('我这coroutine1里面')
        yield '1'
        yield '2'
    
    def coroutine2(n):
        print('我这coroutine2里面')
        yield '3'
        yield '4'
    
    def func(n): print('我在func里面') yield from coroutine1(n) #yield from 相当于1个中间件,可以在1个函数里面 直接 把其他生成器里所有yield的值获取到 yield from coroutine2(n) g=func(2) print(next(g)) print(next(g)) print(next(g)) print(next(g)) ''' 我这coroutine1里面 1 2 我这coroutine2里面 3 4 '''

    yield from新语法

    参考

  • 相关阅读:
    【NOIP2013提高组T3】货车运输-最大生成树+倍增LCA
    【POJ1986】Distance Queries-LCA算法
    【POJ1986】Distance Queries-LCA算法
    【HDU2874】Connections between cities-LCA算法
    【HDU2874】Connections between cities-LCA算法
    【HDU2586】How far away?-LCA算法模板题
    js ajax调用请求
    js ajax调用请求
    ThinkPHP 3.1.2 视图 2
    ThinkPHP 3.1.2 视图 2
  • 原文地址:https://www.cnblogs.com/sss4/p/6683001.html
Copyright © 2011-2022 走看看