zoukankan      html  css  js  c++  java
  • python自动化_day4_迭代器生成器内置函数和匿名函数

    什么是可迭代的   含有__iter__方法的就是可迭代的:
    python 可迭代对象——Iterable
    Python中经常使用for来对某个对象进行遍历,此时被遍历的这个对象就是可迭代对象,
    像常见的list、tuple、dict、set、str都是。如果给一个准确的定义的话,就是只要它
    定义了可以返回一个迭代器的iter方法,或者定义了可以支持下标索引的getitem方法,
    那么它就是一个可迭代对象。
    python 迭代器对象——Iterator
    迭代器是通过next()来实现的,每调用一次他就会返回下一个元素,
    当没有下一个元素的时候返回一个StopIteration异常,所以实际上定义
    了这个方法的都算是迭代器。迭代器一定是可迭代对象,反过来则不一定
    成立。用iter()函数可以把list、dict、str等Iterable变成Iterator
    什么是迭代器 含有__iter__方法和__next__方法的就是迭代器
    Iterable 判断是不是可迭代的。Iterator判断是不是迭代器
    1 l = [1,2,3]
    2 new_l = iter(l)
    3 print(new_l.__next__())
    4 from collections import Iterable,Iterator
    5 print(range(1000000))
    6 print(isinstance(range(10000000),Iterable))
    7 print(isinstance(range(10000000),Iterator))
    py2 rangge 不管range多少 会生成一个列表用来存储所有的值
    py3 range 不管range多少 都不会实际的生成任何一个值
    迭代器的优势:
    节省内存
    取一个值就能进行接下来的计算,而不需要等待所有的值都计算出来才开始接下来的运算--快
    迭代器的特性:惰性运算
    1 for i in range(100):
    2     print(i)
    3 f = open()
    4 for line in f:
    5     print(f)
    列表 字典 元组 字符串 集合 rangge 文件句柄 enumerate  所有能for循环的都是可迭代的,都可以使用next
    方法变成一个迭代器

    生成器 Genareter
    自己写的迭代器就是一个生成器
    两种自己写生成器(迭代器)的机制:生成器函数 生成器表达式

    生成器函数
     1 def close(num):
     2     ret = []
     3     for i in range(num):
     4         ret.append('cloth%s'%i)
     5     return ret
     6 def close_g(num):
     7     for i in range(num):
     8         yield 'cloth%s' %i  #凡是带有yield的函数就是一个生成器函数
     9 g = close_g(10000)
    10 print(g.__next__())
    11 print(g.__next__())
    12 print(g.__next__())
    13 print(g.__next__())
    14 
    15 def func1():
    16     print('1111')
    17     yield 1
    18     print('222222')
    19     yield 2
    20     yield 3     #记录当前所在的位置,等待下一次next来触发函数的状态
    21     yield 4
    22 g = func1()
    23 print(g.__next__())
    24 print(g.__next__())
    25 for i in g:
    26     print(i)
    凡是带有yield的函数就是一个生成器函数
    生成器函数的调用不会触发代码的执行,而是会返回一个生成器(迭代器)
    想要生成器函数执行,需要用next

    s使用生成器监听文件输入的例子
     1 def listen_file():
     2     with open('userinfo') as f:
     3         while True:
     4             line = f.readline()
     5             if line.strip():
     6                 yield line.strip()
     7             time.sleep(0.1)
     8 g = listen_file()
     9 for line in g:
    10     print(line)
    send 关键字
     1 def func():
     2     print(1111)
     3     ret1 = yield 1
     4     print(2222,ret1)
     5     ret2 = yield 2
     6     print(3333,ret2)
     7     yield 3
     8 
     9 g = func()
    10 ret = g.__next__()
    11 print(ret)
    12 g1 = g.send('alex')  #send 就是在执行next的过程中,生成一个参数,给生成器函数的内部
    13 print(g1)
    向生成器中传递值,有一个激活的过程,第一次必须用next触发,后边才可以使用send传参
    例子
    计算移动平均值
    月度 的 天平均收入
    第一天200元收入,第二天300元,第三天500元
    200 250 333.3333
     1 def average():
     2     sum_money = 0
     3     day = 0
     4     avg = 0
     5     while True:
     6         money = yield avg
     7         sum_money += money
     8         day += 1
     9         avg = sum_money / day
    10 g = average()
    11 next(g)
    12 print(g.send(200))
    13 print(g.send(300))

    预激生成器
     1 def init(func):
     2     def inner(*args,**kwargs):
     3         ret = func(*args,**kwargs)
     4         next(ret)  #
     5         return ret
     6     return inner
     7 @init
     8 def average():
     9     sum_money = 0
    10     day = 0
    11     avg = 0
    12     while True:
    13         money = yield avg
    14         sum_money += money
    15         day += 1
    16         avg = sum_money / day
    17 g = average()
    18 next(g)         #预激活
    19 print(g.send(200))
    20 print(g.send(300))
    21 预激活做成装饰器,可以节省很多时间  叫做预激生成器
    22 yield from
    23 def generator_func():
    24     for i in range(5):
    25         yield i
    26     for j  in 'hello':
    27         yield j
    28 
    29 g = generator_func()
    如何从生成器中取值
    第一种 使用next取值 随时可以停止,最后一次会报错
    print(next(g))
    第二种 使用for循环取值 从头到尾遍历一次,不遇到break不停止
    for i in g:
    print(i)
    第三种 list取值或者tuple取值 数据类型的强转 会把所有的数据都加载到内存里,非常的浪费内存
     1 print(g)
     2 print(list(g))
     3 def generator_func():
     4     for i in range(5):
     5         yield i
     6     for j  in 'hello':
     7         yield j
     8     yield from range(5)
     9     yield from 'hello'
    10 g1 = generator_func()
    11 g2 = generator_func()
    12 for i in g:
    13     print(i)
    14 print(g1,g2)
    15 next(g1)
    16 print(next(g1))
    17 print(next(g1))


    生成器函数 是我们python程序员实现迭代器的一种手段
    主要手段,在函数中 含有yield 有yield就不建议使用return
    调用一个生成器函数,不会执行这个函数中的代码,只是会获得一个生成器(迭代器)
    只有从生成器中取值的时候,才会执行函数内部的代码,且每获取一个数据才执行得到这个数据的代码
    获取数据的方式包括, next send 循环数据类型的强制转换
    yield 返回值的简便方法,如果本身就是循环一个可迭代的,且要把可迭代数据中的每一个元素都返回,可以用yield from
    使用send的时候,在生成器创造出来之后需要进行预激活,这一步可以使用装饰器完成
    生成器的特点:节省内存 惰性运算
    生成器用来解决内存问题和程序功能之间的解耦

    列表推导式
    new_list=[]
    for i in range(10):
        new_list.append(i**2)
    print(new_list)
    print([i**2 for i in range(10)])
    print([abs(i) for i in  [1,2,3,-5,6,20,17]])
    
    l = [1,2,3,41,-5]
    print([num for num in l if num%2 == 1])
    #30以内所有能被3整除的数
    print([num for num in range(30) if num%3 == 0])
    #30以内所有能被3整除的数的平方
    print([num**2 for num in range(30) if num%3 == 0])
    #知道嵌套列表中名字含有两个‘e’的所有名字
    names = [['Tom','Billy','Jefferson','Arderm','Wesley','Steven','Joe'],
            ['alice','Jill','Ana','Wendy','Jennifer','Sherry','Eva']]
    print([name for name_list in names for name in name_list if name.count('e') == 2])
    生成器表达式
    #30以内所有能被3整除的数
    l = [num for num in range(30) if num%3 == 0]  #列表推倒式 排序的时候使用列表推导式
    g = (num for num in range(30) if num%3 == 0)  #生成器表达式 庞大数据量的时候使用生成器表达式
    print(l)
    print(g)

    林海峰
    egg_list = ['jidan%s' %i for i in range(10)]  #列表解析多少鸡蛋
    laomuji = ('jidan%s' %i for i in range(10))   #生成器表达式 用一个鸡蛋拿一个鸡蛋
    print(laomuji)
    print(laomuji.__next__())
    print(egg_list)

    面试题
    #第一个
    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))
    
    #第二个
    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)
    
    n = 1
    g = (add(n, i) for i in g)
    下边的g是上边g的生成器表达式 n永远都是最后的10
    n = 10
    g = (add(10, i) for i in (add(10, i) for i in [0,1,2,3])) #(add(10, i) for i in [0,1,2,3])=[10,11,12,13]
    g = (add(10, i) for i in [10,11,12,13])
    g = [20,21,22,23]
    print(list(g))
    
    #第三题  这种问题跟循环前面的数字没关系 只跟最后一个和有多少个有关系。
    def add(n,i):
        return n+i
    def test():
        for i in range(4):
            yield i
    g=test()
    for n in [1,3,10]:
        g = (add(n,i) for i in g)
    n = 1
    g = (add(n,i) for i in g)
    n = 3
    g = (add(n,i) for i in g)
    n = 10
    g = (add(n,i) for i in (add(n,i) for i in (add(n,i) for i in [0,1,2,3])))
    #然后 n = 10 相加
    g = (add(n,i) for i in (add(n,i) for i in [10,11,12,13]))
    g = (add(n,i) for i in [20,21,22,23])
    g = [30,31,32,33]
    print(list(g))
    一个生成器只能取一次值
    生成器在不找他要值的时候,始终不执行
    当他执行的时候,要以执行时候的所有变量值为准


    迭代器
    什么是可迭代的 含有__iter__方法的就是可迭代的:
    python 可迭代对象——Iterable
    Python中经常使用for来对某个对象进行遍历,此时被遍历的这个对象就是可迭代对象,
    像常见的list、tuple、dict、set、str都是。如果给一个准确的定义的话,就是只要它
    定义了可以返回一个迭代器的iter方法,或者定义了可以支持下标索引的getitem方法,
    那么它就是一个可迭代对象。
    python 迭代器对象——Iterator
    迭代器是通过next()来实现的,每调用一次他就会返回下一个元素,
    当没有下一个元素的时候返回一个StopIteration异常,所以实际上定义
    了这个方法的都算是迭代器。迭代器一定是可迭代对象,反过来则不一定
    成立。用iter()函数可以把list、dict、str等Iterable变成Iterator
    什么是迭代器 含有__iter__方法和__next__方法的就是迭代器
    Iterable 判断是不是可迭代的。Iterator判断是不是迭代器

    生成器
    自己写的迭代器就是一个生成器

    生成器函数
    凡是带有yield的函数就是一个生成器函数
    生成器函数的调用不会触发代码的执行,而是会返回一个生成器(迭代器)
    想要生成器函数执行,需要用next

    生成器的预激活过程
    预激活做成装饰器,可以节省很多时间 叫做预激生成器


    列表推倒式 和 生成器表达式
    l = [num for num in range(30) if num%3 == 0] #列表推倒式 排序的时候使用列表推导式
    g = (num for num in range(30) if num%3 == 0) #生成器表达式 庞大数据量的时候使用生成器表达式

    如何从生成器中取值
    第一种 使用next取值 随时可以停止,最后一次会报错
    print(next(g))
    第二种 使用for循环取值 从头到尾遍历一次,不遇到break不停止
    for i in g:
    print(i)
    第三种 list取值或者tuple取值 数据类型的强转 会把所有的数据都加载到内存里,非常的浪费内存

    预激活做成装饰器,可以节省很多时间 叫做预激生成器


    内置函数 不def 定义函数可以直接 加()的都是内置函数
    print()
    input()
    len()
    open()
    tuple()
    list()
    bool()
    set()
    id()
    str()
    abs()
    作用域相关 平时不用
    locals() #返回本地作用域中的所有名字
    globals() #返回全局作用域中的所有名字

    enumerate 可以按照索引和
    l = [1,23,45]
    ret = enumerate(l)
    for i in ret:
    print(i)

    global 变量 关键字 声明函数内部变量对全局生效
    nonlocal 变量 关键字 声明函数内部变量对本层以及下边生效

    迭代器 生成器相关
    range() 是一个可迭代对象 不是迭代器
    range(10)
    range(1,10,2)
    迭代器 .__next__()
    next(迭代器)
    iter() .__iter__()

    其他 dir 查看一个变量拥有的所有方法 不长写在代码里
    print(dir([]))
    dir([])

    callable() 检查一个变量是否可以被调用 后边加() 就是可以被调用的
    print(callable(print))

    help 帮助

    import os 导入模块 __import__()
    某个方法属于某个数据类型的变量,就用.调用
    如果某个方法不依赖于任何数据类型,就直接调用 只有内置函数和自己定义的函数是可以直接调用的
    剩下的所有内容都是属于数据类型的

    open
    f = open('file')
    f.readline()
    f.writable() #可不可以写

    跟内存相关
    id()
    hash()
    对于相同可hash的数据的hash值再一次程序的执行过程中总是不变得
    print(hash(12345))
    print(hash('12312332'))
    print(hash('12312332'))
    print(hash(('1','2')))
    print(hash([])) #不可以哈希

    输入输出相关
    input() #输入一个值才结束
    print(self, *args, sep=' ', end=' ', file=None) # 打印 每一次打印会自动换行
    print('我们的祖国是花园',end = '') #指定输出的结尾
    print('我们的祖国是花园')
    print('我们的祖国是花园')
    print('我们的祖国是花园')

    print(1,2,3,4,5,sep = '|') #sep 指定输出分割符

    指定一个文件 把文件写入一个文件名为f的文件里
    f = open('file','w')
    print('a',file=f)
    f.close()


    打印进度条
    1 import time
    2 for i in range(0,101,2):  #0,2,4,6,8
    3      time.sleep(0.1)
    4      char_num = i//2      #打印多少个'*'     4
    5      if i == 100:
    6          per_str = '
    %s%% : %s
    ' % (i, '*' * char_num)  #
     回到行首
    7      else:
    8         per_str =  '
    %s%% : %s
    '%(i,'*'*char_num)
    9      print(per_str,end='',flush=True)   # 0.01
    exec  eval   都可以执行字符串的看起来是python语句的
    1 exec('print(123)')
    2 eval('print(123)')
    3 print(1+2+3+4)
    4 print(exec('1+2+3+4'))
    5 print(eval('1+2+3+4'))
    两个都可以执行字符串类型的代码  eval有返回值简单的计算,exec没有返回值简单的流程控制
    eva 只能用在你明确知道你要执行的代码是什么
    1 code = '''for i in range(10):
    2         print(i*'*')
    3 '''
    4 exec(code)
    compile()  将字符串进行编译变成字节码  然后用exec 和eval执行

    复数 ---- complex
    实数 ---- 有理数:整数 有限循环小数 无限循环小数 和 无理数:π
    虚数 ---- 虚无缥缈的数
    5 + 12j == 复合的数 == 复数 复数之间不能比较大写

    和数字相关 只在数据类型转换的时候才用
    float 浮点数(有限循环小数 和 无限循环小数) !== 小数:有限循环小数 和 无限循环小数 无线不循环小数
    浮点数
    354.123 = 3.54123*10**2 = 35.4123*10
    f = 1.43287432846824235244645645646
    print(f)


    进制转换
    bin() 二进制
    oct() 八进制
    hex() 十六进制
    0b 二进制
    0o 八进制
    0x 十六进制

    数学运算
    print(abs(-7)) 绝对值
    divmod() 接收两个参数 求商取余 div 是除法 mod 是取余
    print(divmod(10,2))
    print(round(3.12312,2)) #做精确值 会四舍五入
    print(pow(2,3)) #pow 幂运算2的3次方
    print(pow(1,23,4)) # 1的23次幂取余4

    sum min max
    sum 求和必须是可迭代的 必须是数字
    print(sum(range(10)))
    print(sum([1,3,4,5,6],10))


    min(iterable, *[, default=obj, key=func]) -> value
    min(arg1, arg2, *args, *[, key=func]) -> value
    print(min([1,23,4,5,]))
    print(min(1,23,4,-4))
    print(min([111,-23,4,5],key=abs),) #可以添加参数key 以绝对值的求最小值
    max(*args, key=None) #可以添加参数key 以绝对值的求最小值
    ##数据类型有多少:int str list tuple set dict bool。。。。。
    ##数据结构有多少:容器数据类型list tuple set dict str
    ##重要的内置函数 reverse
    l = [1,23,4]
    l.reverse() #翻转
    print(l)
    l = [1,2,34,5,6]
    l2 = reversed(l) #反转之后成生一个迭代器 不改变原来的列表 保留原来的列表生成一个反序迭代器
    print(list(l2))

    slice
    l = (1,2,3,421,321,3,2131,321)
    sli = slice(1,5,2)
    print(l[sli])


    format 如果以后对数学相关可以使用format
    print(format('test','<20'))
    print(format('test','>20'))
    print(format('test','^20'))


    ###bytes 转换成bytes类型
    我拿到的是gbk编码,想转换成utf-8类型 需要先转换成Unicode类型在转换成bytes的utf-8

    bytearray byte类型的数组
    print(bytearray('ninhao',encoding='utf-8'))

    l = '2132134214sdasasdsadsa'
    memoryview 切片内存
    ord() #字符串转换成数字
    chr() #数字转换成字符串
    ascii()

    print(repr('1'),repr(1)) #可以原封不动的打印出来
    name = 'egg'
    print('nihao%r' %name)

    dict set
    frozenset #集合不可变

    最重要的几个 len enumerate zip filter map sorted
    all 可迭代的 如果里面有一个FALSE就是FALSE
    any 可迭代的 有一个True就是True

    zip #拉链 可迭代的 把两个拉到一起组成新的展示 按照最短的
    l = [1,2,3]
    l2 = ['a','b','c']
    l3 = (1,3,4)
    l4 = {'k':1,'v':2}
    for i in zip(l,l2,l3,l4):
    print(i)

    filter() 跟生成器表达式,列表推导式类似 必须跟函数的名字一起使用 用于筛选
     1 def is_odd(x):
     2     return x and str(x).strip()
     3 ret = filter(is_odd, ['',None,' ',1,2,3,4,7,9]) #filter 生成一个迭代器 节省内存
     4 for i in ret:
     5     print(i)
     6 print([i for i in [1,2,3,4,7,9] if i % 2 == 1])
     7 from math import sqrt
     8 def m(x):
     9     return sqrt(x) % 1 == 0
    10 ret = filter(m,range(100))
    11 print(list(ret))
    12 for i in ret:
    13     print(i)

    map()
    1 ret = map(abs,[1,-4,5,19])
    2 print(ret)
    3 for i in ret:
    4     print(i)

    filter 执行了filter之后的结果集合一定是<= 执行之前的个数
    filter 只管筛选,不会改变原来的值
    map 元素执行前后个数不变,值可能改变了

    sorted 排序 是可迭代的 可以根据要求排序

    l = [1,3,4,-5,-7]
    l.sort(key=abs) #sort 在愿列表的基础上进行排序
    print(l)
    l1 = sorted(l,key=abs) #生成一个全新的列表 排序必须读取所有的数据才可以排序,消耗内存
    print(l1)

    练习
    l = [' ',[1,2],'hello','wordle']
    l1 = sorted(l,key=len)
    print(l1)



    匿名函数 lambda
    1 cale = lambda n:n**n
    2 print(cale(10))
    3 add = lambda a,b:a+b
    4 print(add(1,2))
    5 dic = {'k1':1,'k2':3,'k3':1}
    6 print(dic[max(dic,key=lambda k:dic[k])])
    7 
    8 res = filter(lambda x:x>10,[5,8,11,9,15])
    9 print(list(res))

    带key的内置函数:max mix filter map sorted 都可以跟key参数使用 或者说都可以跟lanbda合作
    1 d = lambda p:p*2
    2 t = lambda p:p*3
    3 x = 2
    4 x = d(x)   # x = 4
    5 x = t(x)   # x = 12
    6 x = d(x)
    7 print(x)

    现有两元组(('a'),('b')),(('c'),('d')),请使用python中匿名函数生成列表[{'a':'c'},{'b':'d'}]
    匿名函数 == 内置函数和匿名函数组合 max min map filter sorted
    1 ret = zip((('a'),('b')),(('c'),('d')))
    2 ('a', 'c') ('b', 'd')
    3 def func(tup):
    4     return {tup[0]:tup[1]}
    5 res  = map(lambda tup:{tup[0]:tup[1]},ret)
    6 print(list(res))


    3.以下代码的输出是什么?请给出答案并解释。
    1 def multipliers():
    2     return [lambda x:i*x for i in range(4)]
    3 print([m(2) for m in multipliers()])
     
  • 相关阅读:
    instance of type of object.prototype.tostring 区别
    字符串属性及方法大总结
    数组属性及方法大总结
    在Vue中遇到的各种坑 及性能提升
    find、filter、map的区别
    react 的CDN 连接
    react开启一个项目 webpack版本出错
    react中的jsx详细理解
    Vue 在beaforeCreate时获取data中的数据
    vue点击时动态改变样式 ------- 最简单的方法
  • 原文地址:https://www.cnblogs.com/tewu/p/8992423.html
Copyright © 2011-2022 走看看