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新语法

    参考

  • 相关阅读:
    Interview with BOA
    Java Main Differences between HashMap HashTable and ConcurrentHashMap
    Java Main Differences between Java and C++
    LeetCode 33. Search in Rotated Sorted Array
    LeetCode 154. Find Minimum in Rotated Sorted Array II
    LeetCode 153. Find Minimum in Rotated Sorted Array
    LeetCode 75. Sort Colors
    LeetCode 31. Next Permutation
    LeetCode 60. Permutation Sequence
    LeetCode 216. Combination Sum III
  • 原文地址:https://www.cnblogs.com/sss4/p/6683001.html
Copyright © 2011-2022 走看看