zoukankan      html  css  js  c++  java
  • 13t天 迭代器,生成器,内置函数

    上周复习:

    函数的递归调用

    函数调用时函数嵌套调用的一种特殊形式

    函数在调用时,直接或间接调用了自身,就是梯归调用.

    直接调用自身

    def f1():
      print('from f1')
      f1()
    f1()

    间接调用函数

    def f1():
      print('from f1')
      f2()

    def f2():
      print('from f2')
      f1()
    f1()
    梯归

    递归应该分为两个明确的阶段,回溯与递推. 回溯就是从外向里一层一层递归调用下去,回溯阶段必须要有一个明确地结束条件,每进入下一次递归时,问题的规模都应该有所减少(否则,单纯地重复调用自身是毫无意义的)

    递推就是从里向外一层一层结束递归

    例子

    # 梯归  5个人猜年龄  每个人都是比前一个大2,第5个30


    def age(a):
       if a == 5:
           return 30
       return age(a+1)-2
    res = age(1)
    print(res)
    二分
    算法:高效率解决问题的方法
    二分法必须基于一个有序的容器类型,容器类型里面的数字必须有大小顺序
    判断某个值在不在列表内

    每次截取上一次容器类型一半进行比较

    l = [1,2,3,45,67,90,123,234,689,990...]
    target_num = 980
    middle_index = l//2
    # 利用列表的切片操作截取 小列表
    例子
    a = [1,2,3,5,7,9,10,32,42,50,64,72,80,94,99,101,]

    # 效率低
    # num = 5
    # for i in a:
    #     if i == 5:
    #         print('find')
    target_num = 72
    def get_num(a,target_num):
       if not a:
           print('')
       # 得到中间的索引
       zhong_index = len(a) // 2
       #     判断中间的数字和要得到的数字是否一致
       if target_num > a[zhong_index]:
           num_right = a[zhong_index + 1:]
       #         在递归调用get_num函数
           get_num(num_right,target_num)
       elif target_num <a[zhong_index]:
           left_num = a[0:zhong_index]
           get_num(left_num,target_num)
       else:
           print('找',zhong_index)
       get_num(a,target_num)
    三元表达式

    三元表达式的应用场景只推荐只有两种的情况的可能下使用

    三元表达式固定表达式
       值1 if 条件 else 值2
           条件成立 值1
           条件不成立 值2
    x = 1
    y = 2
    res = x if x > y else y
    结果1 if 条件 else 结果2
    条件成立返回结果1
    条件不成立返回结果2
    如果if后面的条件成立返回if前面的值 否则返回else后面的值

    例子

    is_free = input(>>>:)
    is_free = '免费' if is_free == 'y' else '收费'
    列表/字典/集合生成式
    a = ['tank','owen','egon','nick','seam']
    aa = []
    for name in a:
       aa.append('%s_sb'%name)
       print(aa)
    print(aa)
    res1 = ['%s_qw'%name for name in a]
    print(res1)
    a2 = ['tank_qw', 'owen_qw', 'egon_qw', 'nick_qw', 'seam_qw','we_we']
    res2 = [name for name in a2 if name.endswith('_qw')]
    # 先for循环依次取出列表里面的每一个元素
    # 然后交由if判断 条件成立才会交给for前面的代码
    # 如果条件不成立 当前的元素 直接舍弃
    q = ['name','password','hobby']
    q1 = ['owen','123','read']

    dic = {}
    for i ,o in enumerate(q):
       print(i,o)
       # print(i , o)
       dic[o] = q1[i]
       print(dic)
    print(2222)
    res3 = {q:a for q,a in enumerate(q)}
    print(res3)
    l1 = [i for i in range(10)]
    l2 = [i for i in range(10) if i != 4]  # 注意只能跟if不能再跟else了
    匿名函数

    没有名字的函数

    匿名函数通常不会单独使用,是配合内置函数一起使用的

    匿名函数的特点:

    临时存在用完就没了

    关键字:

    lambda

    lambda 形参:返回值
    1.当场定义当场调用
              (lambda 形参:返回值)()
    2.给匿名命名
               func = lambda x:x**2
               func()
    3.匿名函数通常都是配合其他函数(内置函数,自定义函数)一起使用

    例子

    res = (lambda x,y:x+y)(1,2) 
    print(res)
    func = lambda x,y:x+y
    print(func(1,2))

    # :左边的相当于函数的形参
    # :右边的相当于函数的返回值
    常用的内置函数
    max:内部基于for循环,先一个个将传入的容器类型中的元素一个个取出
       当你没有指定key(key对应的是一个函数)的时候 就按照for循环取出来的值比较大小
       如果指定了key,那么max会将元素交给这个函数,拿着该函数返回结果来做大小比较
     

    max:最大

    d = {
       'jason': 1000,
       'egon': 888888888,
       'tank': 300000,
       'nick': 400000,
    }


    def func(name):
       return d[name]

    print(max(d))
    print(max(d, key=func))
    print(max(d, key=lambda name: d[name]))

    min:最小

    min:
    d = {
       'jason': 1000,
       'egon': 888888888,
       'tank': 300000,
       'nick': 400000,
    }


    def func(name):
       return d[name]

    print(min(d))
    print(min(d, key=func))
    print(min(d, key=lambda name: d[name]))

    zip:拉链

    zip 拉链  # 基于for循环
    l1 = [1,2,]
    l2 = ['jason','egon','tank']
    l3 = ['a','b','c']
    print(list(zip(l1,l2,l3)))
    # 基于for循环

    map:映射

    map:映射
    l = [1,2,3,4,5,6]
    # print(list('hello'))
    print(list(map(lambda x:x+5,l)))
    # 基于for循环

    filter:过滤

    l = [1,2,3,4,5,6]
    print(list(filter(lambda x:x != 3,l)))  
    # 基于for循环

    sorted:排序

    l = ['jason','egon','nick','tank']
    print(sorted(l,reverse=False))

    reducel:合并

    from functools import reduce
    l = [1,2,3,4,5,6]
    print(reduce(lambda x,y:x+y,l,19))
    # 19初始值 为第一个参数
    # 当初始值不存在的情况下 按照下面的规律
    # 第一次先获取两个元素 相加
    # 之后每次获取一个与上一次相加的结果再相加
    无参装饰器
    from functools import wraps
    def outter(func):
       @wraps(func)
       def inner(*args,**kwargs):  # * **在形参中使用
           # 执行被装饰函数之前你可以做的操作
           res = func(*args,**kwargs)  # * **在实参中使用
           # 执行被装饰函数之后你可以做到操作
           return res
       return inner

    @outter
    def index(username,*args,**kwargs):
       """index注释"""
       pass
    print(index)
    装饰器修复技术
    1.返回原来的函数的函数名
    2.返回原来的函数的注释
    from functools import wraps
    @wraps(func)
    有参装饰器
    def wrappers(data):
      # data = 'file'
      def outter(func):
          def inner(*args,**kwargs):
              if data == 'file':
                  # 执行被装饰函数之前你可以做的操作
                  res = func(*args,**kwargs) # * **在实参中使用
                  # 执行被装饰函数之后你可以做到操作
                  return res
          return inner
      return outter
    今日内容
      迭代器
      可迭代对象
      迭代器对象
      for循环内部原理
      生成器
      面试题
      生成器表达式
      内置函数
      面向过程编程

    day13

    迭代器

    迭代:是一个重复的过程,每次重复即一个迭代,并且每次重复的结果都是下一次迭代的初始值

    为什么用迭代:

    序列类型:字符串、列表、元组,可以使用索引的方式迭代取出其包含的元素。但对于字典、集合、文件等类型是没有索引的,而提供了一种不依赖索引取值的方法

    n = 0
    while True:
    print(n)
    不算,只是单纯的重复
    s = 'hello word'
    count=0
    while count < len(s): #迭代
       print(s[count])
       count +=1
    可迭代对象

    可迭代对象指的是内置有__iter__方法的对象,即__obj__.

    可迭代对象执行obj.__iter__()得到的结果就是迭代器对象
    基本数据类型中
      是可迭代对象的有
          str list tuple dict set
          文件对象(执行内置的__iter__之后还是本身 没有任何变化):文件对象本身就是迭代器对象
           
    迭代器对象
    迭代器对象指的是即内置有__iter__又内置有__next__方法的对象

    文件类型是迭代器对象
    open('a.txt').__iter__()
    open('a.txt').__next__()
    迭代器对象无论执行多少次__iter__方法得到的还是迭代器对象本身

    例子

    i = 1
    f = 1.2
    s = 'hello'
    l = [1,2,3,]
    t = (1,2,3)
    set = {1,2,3,4}
    d = {'name':'abo','password':1230}
    f1 = open('a.txt','r',encoding='utf=8')
    s.__iter__()
    l.__iter__()
    t.__iter__()
    a1 = d.__iter__()
    print(a)
    #也可以简化成
    res = iter(d)
    f1.__iter__()
    f1.__next__()

    迭代器取值

    l =[1,2,3,4,5,6,7,8,9,]
    # 生成一个迭代器对象
    # iter_l = l.__iter__()
    iter_l = iter(l)
    # 迭代器对象取值 调用__next__的方法
    print(iter_l.__next__())
    print(iter_l.__next__())
    print(iter_l.__next__())
    print(iter_l.__next__())
    print(iter_l.__next__())
    print(iter_l.__next__())
    print(iter_l.__next__())
    print(iter_l.__next__())
    print(iter_l.__next__())
    print(iter_l.__next__())
    print(iter_l.__next__())
    print(iter_l.__next__())
    #报错是因为将值取完了,没有值可以取 报错StopIteration
    d = {'name':'obao','password':'123','hobby':'eat'}
    #生成一个迭代器对象
    iter_d = d.__iter__()
    #迭代器对象的取值必须用__naxt__的方法
    #print(iter_d.__next__())
    #print(iter_d.__next__())
    #print(iter_d.__next__())
    #print(iter_d.__next__())   # 取完了 报错StopIteration
    捕获异常
    while True:
       try:
           print(iter_d.__next__())
       except StopIteration:
           print('无值')
           break

    迭代器对象一定是可迭代对象,而可迭代对象不一定是迭代对象.

    迭代器取值的特点:

    优点:

    1. 提供一种统一的、不依赖于索引的迭代方式

    2. 惰性计算,节省内存

    缺点:

    1.只能往后依次取值 不能往前退

    2.无法获取长度,不能获取指定的长度

    for循环内部原理
    for循环内部的本质
       1.将in后面的对象调用__iter__转换成迭代器对象
       2.调用__next__迭代取值
       3.内部有异常捕获StopIteration,当__next__报这个错 自动结束循环
    l = [1,2,3,4]
    for i in l:
       print(i)
    a = [1,2,3,4]
    # for i in a:
    #     print(i)
    # print(len(a))
    res = map(lambda x:x+1,a)
    # a = list(map(lambda x:x+10,a))
    print(a)
    print(res.__next__)
    生成器

    用户自定义的迭代器,本质就是迭代器.

    def func():
       print(11111)
       yield  # 函数内如果有yield关键字,那么加括号执行函数的时候并不会触发函数体代码的运行
    # 写出1,100之间的奇数
    for i in range(1,100,2)
    print(i)
       
       
    def my_range(start,end,step=1):
       while start < end:
           yield start
           start += step

    for j in my_range(1,100,2):
    print(j)

    yield支持外界为其传参

    def people(name):
       print('%s 准备吃'%name)
       while True:
           food = yield
           print('%s吃了%s'%(name,food))

    #当函数内有yield关键字的时候,调用该函数不会执行函数体代码
    # 而是将函数变成生成器
    a = people('bobo')
    a.__next__()    # 必须先将代码运行至yield 才能够为其传值
    a.send('包子')   # 给yield左边的变量传参 触发了__next__方法
    a.send('饺子')
    yield
       1.帮你提供了一种自定义生成器方式
       2.会帮你将函数的运行状态暂停住
       3.可以返回值

    与return之间异同点
       相同点:都可以返回值,并且都可以返回多个
       不同点:
           yield可以返回多次值,而return只能返回一次函数立即结束
           yield还可以接受外部传入的值
    生成器表达式
    res = (i for i in range(1,10)if i!= 3)
    # 生成器表达式
    """
    生成器不会主动执行任何一行代码
    必须通过__next__触发代码的运行
    """
    print(res)
    print(res.__next__())
    print(res.__next__())
    print(res.__next__())

    应用场景:

    1.要在一个很大的容器中获得值

    res = (i for i in range(1,100000000) if i != 4)  # 生成器表达式
    print(res)
    print(res.__next__())
    print(res.__next__())
    print(res.__next__())

    2.统计字符个数

    # 占内存
    f = open('xxx.txt','r',encoding='utf-8')
    data = f.read()
    print(len(data))
    f.close()


    with open('xxx.txt','r',encoding='utf-8') as f:
       # n = 0
       # for line in f:
       #     n += len(line)
       # print(n)
       g = (len(line) for line in f)
       # print(g.__next__())
       # print(g.__next__())
       # print(g.__next__())
       # print(g.__next__())
       print(sum(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)
       # 第一次for循环g=(add(n,i) for i in test())

       # 第二次for循环g=(add(n,i) for i in (add(n,i) for i in test()))
    print(n)
    res=list(g)

    """
    for i in (add(10,i) for i in test()): 会执行所有的生成器内部的代码
      add(n,i)
    """




    #A. res=[10,11,12,13]
    #B. res=[11,12,13,14]
    #C. res=[20,21,22,23] 答案
    #D. res=[21,22,23,24]

     

     

    内置函数

    abs:求平均值

    print(abs(-11.11)

    all,any

    print(all(l))  # 只要有一个为False就返回False
    print(any(l))  # 只要有一个位True就返回True

    locals,globals

    def index():

       username = '我是局部名称空间里面的username'
       # print(locals()) # 当前语句在哪个位置 就会返回哪个位置所存储的所有的名字
       print(globals())  # 无论在哪 查看的都是全局名称空间
    index()

    bin,oct,hex

    print(bin(10))
    #转换成二进制
    print(oct(10))
    #转换成八进制
    print(hex(10))
    #转换成十六进制
    print(int('0b1010',2))
    # 转换为整数

    bool True,False

    print(bool(1))
    print(bool(0))

    bytes :转换二进制字符

    s = 'hello'
    print(s.encode('utf-8'))
    print(bytes(s,encoding='utf-8'))

    callable:可被加括号调用的执行相应功能的

    l = [1,2,3]
    def index():
       pass
    print(callable(l))
    print(callable(index))

    chr,ord

    print(chr(97))  # 将数字转换成ascii码表对应的字符
    print(ord('a'))  # 将字符按照ascii表转成对应的数字

    dir:dir获取当前对象名称空间里面的名字

    l = [1,2,3]
    print(dir(l))

    import test
    print(dir(test))
    print(test.name)

    divmod:分页器

    print(divmod(101,10))
    total_num,more = divmod(900,11)
    if more:
       total_num += 1
    print('总页数:',total_num)

    enumerate:枚举

    l = ['a','b']
    for i,j in enumerate(l,1):
       print(i,j)

    eval,exec

    s = """
    print('hello baby~')
    x = 1
    y = 2
    print(x + y)

    """
    # eval(s)
    exec(s)
    # eval不支持逻辑代码,只支持一些简单的python代码
    # exec解释并执行字符串,

    format

    # {}占位
    # {index} 索引
    # {name} 指名道姓

    help:帮助

    def login():
       """
      一起嗨皮
      :return:
      """
    print(help(login))

    isinstance:后面统一改方法判断对象是否属于某个数据类型

    n = 1
    print(type(n))
    print(isinstance(n,list))  # 判断对象是否属于某个数据类型
    print(pow(2,3))
    相当于2**3,如果是pow(2, 3, 5),相当于2**3 % 5
    print(round(3.4))
    # 四舍五入取整
    面试过程编程

    面向过程是一种编程思路、思想,而编程思路是不依赖于具体的语言或语法的。言外之意是即使我们不依赖于函数,也可以基于面向过程的思想编写程序

    面向过程编程:就类似于设计一条流水线
       好处:
           将复杂的问题流程化 从而简单化
       坏处:
           可扩展性较差   一旦需要修改 整体都会受到影响

    例子:

    # 注册功能
    # 1.获取用户输入
    def get_info():
       while True:
           username = input(">>>:").strip()
           if not username.isalpha():  # 判断字符串不能包含数字
               print('不能包含数字')
               continue
           password = input('>>>:').strip()
           confirm_password = input("confirm>>>:").strip()
            if password == confirm_password:
    operate_data(username,password)
                   break
           else:
               print('两次密码不一致')

    # 2.处理用户信息
    def operate_data(username,password):
       # jason|123
       res = '%s|%s '%(username,password)
       save_data(res,'userinfo.txt')

    # 3.存储到文件中
    def save_data(res,file_name):
       with open(file_name,'a',encoding='utf-8') as f:
           f.write(res)

    def register():
       get_info()

    register()
    def get_info():
       while True:
           username = input(">>>:").strip()
           if not username.isalpha():  # 判断字符串不能包含数字
               print('不能包含数字')
               continue
           password = input('>>>:').strip()
           confirm_password = input("confirm>>>:").strip()
           if password == confirm_password:
               d = {
                   '1':'user',
                   '2':'admin'
              }
               while True:
                   print("""
                      1 普通用户
                      2 管理员
                  """)
                   choice = input('please choice user type to register>>>:').strip()
                   if choice not in d:continue
                   user_type = d.get(choice)
                   operate_data(username,password,user_type)
                   break
           else:
               print('两次密码不一致')

    # 2.处理用户信息
    def operate_data(username,password,user_type):
       # jason|123
       res = '%s|%s|%s '%(username,password,user_type)
       save_data(res,'userinfo.txt')

    # 3.存储到文件中
    def save_data(res,file_name):
       with open(file_name,'a',encoding='utf-8') as f:
           f.write(res)

    def register():
       get_info()

    register()
    面试题:
       请写出一下代码的执行结果并解释。
    def multipliers():

       return [lambda x:i*x for i in range(4)]

       print([m(2) for m in multipliers()])
       
       #0,1,2,3
       # [func(x): return 0*x, func(x): return 1*x,
       # func(x): return 2*x, func(x): return 3*x, ]
       # [func(x): return 0*2, func(x): return 1*2,
    # func(x): return 2*2, func(x): return 3*2, ]

    # 闭包函数的延迟绑定
    # 在内层函数执行时才会绑定变量i
    def a2():
       list1 = []
       for i in range(4):

           def func(x):

               return x * i

           list1.append(func)

       return list1

    print([m(2) for m in as2()])
    # [6, 6, 6, 6]  
       
    def multipliers():

       return [lambda x, i=i: i*x for i in range(4)]
       # 0, 1, 2, 3
       # [func(x): return 0*x, func(x): return 1*x,
       # func(x): return 2*x, func(x): return 3*x, ]

    print([m(2) for m in multipliers()])  # [0, 2, 4, 6]

    # [func(x): return 0*2, func(x): return 1*2,
    # func(x): return 2*2, func(x): return 3*2, ]
    # [0, 2, 4, 6]


    # 闭包函数的延迟绑定
    # 在内层函数执行时才会绑定变量i
    def multipliers():
       list1 = []
       for i in range(4):

           def func(x, i=i):

               return x * i

           list1.append(func)

       return list1

    print([m(2) for m in multipliers()])  # [0, 2, 4, 6]
    '''
    需求: 读取一个文件并返回每行数据的长度
    '''

    with open('test1.txt', 'w', encoding='utf-8') as f:
       for line in range(1000):
           f.write(f'www{line}aaa' * (line + 1) + ' ')


    # 列表推导式: 处理数据量大的文件会导致内存溢出.
    res = [len(line) for line in open('test1.txt', 'r', encoding='utf-8')]
    # print(res)


    # 生成器表达式: 处理数据量大的文件推荐使用.
    res2 = (len(line) for line in open('test1.txt', 'r', encoding='utf-8'))
    print(res2)  # <generator object <genexpr> at 0x000002B3748FD0A0>
    print(next(res2))
    print(next(res2))
    # <gen..>1 (0, 1, 2, 3)

    g = demo()

    g1 = (i for i in g)  # <gen..>2 (0, 1, 2, 3)
    g2 = (i for i in list(g1)) # []

    print(list(g))  # []
    print(list(g1))  # []
    print(list(g2))  # [0, 1, 2, 3]



    # g,g1,g2里面的值都是指向同一个内存地址.

    真实结果:
      [0, 1, 2, 3]
      []

  • 相关阅读:
    JS匿名函数及调用及闭包
    js的变量提升和函数提升
    JS调用模式以及bind()方法
    转载:JS call()方法和apply()方法
    创建一个用于上传文件的表单
    POST 异步请求 url没有明文显示
    转载:nodejs res.end和res.send 区别
    HTTP中get和post区别
    通读cheerio API
    转载:JS数组reduce()和reduceRight()方法
  • 原文地址:https://www.cnblogs.com/komorebi/p/11191949.html
Copyright © 2011-2022 走看看