匿名函数,内置函数,闭包

2023-01-31 00:01:48 函数 匿名
  1. 内容

    1. 匿名函数:一句话函数,比较简单的函数。 函数名 = lambda 参数 : 返回值

      1. 此函数不是没有名字,他是有名字的,他的名字就是你给其设置的变量,比如func。 func() 函数执行

      2. lambda 是定义匿名函数的关键字,相当于函数的def.

      3. lambda 后面直接加形参,形参加多少都可以,只要用逗号隔开就行。

        #所有类型的形参都可以加,但是一般使用匿名函数只是加位置参数,其他的用不到
        func = lambda a,b,*args,sex= 'alex',c,**kwargs: kwargs
        print(func(3, 4,c=666,name='alex'))  # {'name': 'alex'}
      4. 返回值在冒号之后设置,返回值和正常的函数一样,可以是任意数据类型。

      5. 匿名函数不管多复杂.只能写一行.且逻辑结束后直接返回数据.

      练习:

      def func(a,b):
          return a + b
      print(func(4,5))
      
      # 构建匿名函数
      func1 = lambda a,b: a + b
      print(func1(1,2))
      
      • 接收一个可切片的数据,返回索引为0与2的对应的元素(元组形式)。

      • func2 = lambda a: (a[0],a[2])
        print(func2([22,33,44,55])) #(22,44)
        print(func2('asdfg'))  #('a', 'd')
      • 写匿名函数:接收两个int参数,将较大的数据返回。

      • func = lambda a,b: a if a > b else b
        print(func(5,7)) # 7
    2. 内置函数

      # # python 提供了68个内置函数。
      
        reversed() 内建函数将返回一个反序访问的迭代器。 enumerate() 内建函数同样也返回迭代器。
      和range类似,map 、zip以及filter内置函数在Python 3.0 中也转变成迭代器以节约内存空间。
      
      #print()
          ''' 源码分析
          def print(self, *args, sep=' ', end='\n', file=None): # known special case of print
              """
              print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=False)
              file:  默认是输出到屏幕,如果设置为文件句柄,输出到文件
              sep:   打印多个值之间的分隔符,默认为空格
              end:   每一次打印的结尾,默认为换行符
              flush: 立即把内容输出到流文件,不作缓存
              """
          '''
          print(1,2,3,4)#1 2 3 4
          print(1,2,3,4,sep='&')#1&2&3&4
          print(1,2,3,sep='*')#1*2*3
      
          print(111,end='')
          print(222)#两行的结果:111222
      
          f = open('log','w',encoding='utf-8')
          print('写入文件',file=f,flush=True)
      
      #int()
      
      #str()
      
      #bytes() 把字符串转换成bytes类型
           # 将字符串转换成字节
           s = '你好'
           bs = bytes(s,encoding='utf-8')
           print(bs) #b'\xe4\xbd\xa0\xe5\xa5\xbd'
      
           # 将字节转换成字符串
           bs = b'\xe4\xbd\xa0\xe5\xa5\xbd'
           s1 = str(bs,encoding='utf-8')
           print(s1) #你好
      
      #bool()
      
      #set()
      
      # list() 将一个可迭代对象转换成列表
           l1 = list()  #空列表
           l2 = list('abcd')
           print(l2)#['a', 'b', 'c', 'd']
      
      #tuple()  将一个可迭代对象转换成元组
           tu1 = tuple('abcd')
           print(tu1)#('a', 'b', 'c', 'd')
      
      # dict 创建字典的几种方式
          # 直接创建 
            dic = {'name': '太白', 'age': 18}
          # 元组的解构
               dic = dict([(1,'one'),(2,'two'),(3,'three')]   
          #       
               dic = dict(one=1,two=2,three=3)
               print(dic)#{'one': 1, 'two': 2, 'three': 3}
          # fromkeys
               dic = { k: v for k,v in [('one', 1),('two', 2),('three', 3)]}
               print(dic)#{'one': 1, 'two': 2, 'three': 3}
          # update
              dic = {}
              dic.update([(1, 'a'), (2, 'b'), (3, 'c'), (4, 'd')])
              print(dic)#{1: 'a', 2: 'b', 3: 'c', 4: 'd'}
          # 字典的推导式
               dic = { k: v for k,v in [('one', 1),('two', 2),('three', 3)]}
               print(dic)#{'one': 1, 'two': 2, 'three': 3}
      
               lst1 = ['jay', 'jj', 'meet']
               lst2 = ['周杰伦','林俊杰','元宝']
               dic = { lst2[i]: lst1[i] for i in range(len(lst1))}
               print(dic)#{'周杰伦': 'jay', '林俊杰': 'jj', '元宝': 'meet'}
         #
               dic = dict(zip(['one', 'two', 'three'],[1, 2, 3]))
               print(dic)#{'one': 1, 'two': 2, 'three': 3}
      
      # abs()  返回绝对值***
           i = -5
           print(abs(i))#5             
           print(abs(-6))
      
      # sum()求和【针对数字】,可以设置初始 ***
           print(sum([1.1,2.4,3.88]))#7.38
           print(sum([1,2,3]))#6
           print(sum((1,2,3),100))#106  可以设置初始值,让初始值为100
      
           l1 = [i for i in range(10)]
           print(sum(l1))#45
           print(sum(l1,100))#145
      
           s1 = '12345'  #字符串
           print(sum(s1))  # 错误
      
      # reversed  返回的是一个翻转的迭代器(将一个序列翻转, 返回翻转序列的迭代器)  ***
      
           l1 = [i for i in range(10)]
           l1.reverse()  # 列表的方法
           print(l1)#[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]#对原列表操作
      
           ret = reversed([1, 4, 3, 7, 9])
           print(list(ret))  # [9, 7, 3, 4, 1]
      
           l1 = [i for i in range(10)]
           obj = reversed(l1) #将可迭代对象转化为迭代器 返回的是迭代器
           print(obj)#<list_reverseiterator object at 0x000002092EC877F0>
           print(l1)#[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] #原列表不变
           print(list(obj))#[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]转化为列表进行取值
      
      # zip 拉链方法  ***面试题会考
       函数用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的内容,如果各个迭代器的元素个数不一致,则按照长度最短的返回。 
      
          l1 = [1, 2, 3, 4, 5]
          tu1 = ('太白', 'b哥', '德刚')
          s1 = 'abcd'
          obj = zip(l1,tu1,s1)
          print(obj)#<zip object at 0x00000284D0211088>  python内部提供的迭代器
          for i in obj:
               print(i)
          #结果:   
          (1, '太白', 'a')
          (2, 'b哥', 'b')
          (3, '德刚', 'c')                    
          或:
          print(list(obj))#[(1, '太白', 'a'), (2, 'b哥', 'b'), (3, '德刚', 'c')]
      
      # *************  以下方法最最最重要
      
      # min()求最小值 和 max()求最大值
      
          # 返回此序列最小值
          l1 = [33, 2, 3, 54, 7, -1, -9]
          print(min(l1))#-9
          print(min([1,2,-5]))#-5   
      
          # 以绝对值的方式获取最小值
           #1:求最小的绝对值              
           l1 = [33, 2, 3, 54, 7, -1, -9]
           l2 = []
           func = lambda a: abs(a)
           for i in l1:
               l2.append(func(i))
           print(l2)#[33, 2, 3, 54, 7, 1, 9]
           print(min(l2)) #1
      
          #2:找出绝对值最小的元素
              #自己写函数               
              l1 = [33, 2, 3, 54, 7, -1, -9] 
              def abss(a):
                   return abs(a)
              print(min(l1,key=abss)) #-1
              #直接用内置函数abs()
              l1 = [33, 2, 3, 54, 7, -1, -9]
              print(min(l1,key=abs))#-1
      
              print(min([1,2,-5,],key=abs)) #1  ## key=函数名,按照绝对值的大小,返回此序列最小值
      
              print(min(-5,6,-3,key=lambda x:abs(x)))# -3    可以设置很多参数比较大小
      
          【凡是可以加key的:它会自动的将可迭代对象中的每个元素按照顺序传入key对应的函数中,以返回值比较大小。】                
          【 min函数循环的是什么,返回的就是什么。正常情况下:列表:返回列表中的元素。字典:返回字典的键。】
      
          【 加key,是可以加'函数名',min自动会获取传入min函数中的参数的每个元素,然后通过函数的返回值比较大小((key=函数名,看该函数返回的是什么。按照什么比较大小,就将什么设置为返回值),返回最小的返回值对应的那个传入参数的元素。】
      
      
         dic = {'a': 3, 'b': 2, 'c': 1}
          # 求出值最小的键
          print(min(dic))  #a  min默认会按照字典的键去比较大小。
      
          #按照字典的值比较大小 
            #1:                                             
          dic = {'a':3,'b':2,'c':1}
          def func(a):
              return dic[a]  #key对应的函数的返回值是什么,就按什么比较大小
          print(min(dic,key=func))#c   
      
            #2:min函数按照什么循环,lambda函数的参数位置就写什么。后面的返回值是根据它转化的。                                             
          dic = {'a':3,'b':2,'c':1}
          func = lambda a :dic[a]
          print(min(dic,key=func))#c  
           #简化:
           # a为dic的key,按lambda的返回值(即dic的值dic[a])进行比较,返回最小的值对应的键。
          dic = {'a':3,'b':2,'c':1}
          print(min(dic,key=lambda a:dic[a])) # c      字典中最小值对应的键。min函数循环的是什么,返回的就是什么。按键循环
          print(dic[min(dic,key=lambda a:dic[a])]) #1  字典中最小的值                                                      
      
          l2 = [('太白', 18), ('alex', 73), ('wusir', 35), ('口天吴', 41)]
          print(min(l2)) #('alex', 73)    #min函数返回元组,它循环的是什么,返回的就是什么。默认按照列表中每个元组中第一个元素的首字母的Unicode比较                                   
          #自定制,+key
          print(min(l2,key=lambda x:x[1]))#('太白', 18)
          print(min(l2,key=lambda x:x[1])[0])#太白
          print(min(l2,key=lambda x:x[1])[1])#18
      
          # max最大值   与最小值用法相同
      
      
      # sorted  排序函数(可加key自定制)
            语法:sorted(iterable,key=None,reverse=False)
            iterable : 可迭代对象
            key: 排序规则(排序函数),在sorted内部会将可迭代对象中的每一个元素传递给这个函数的参数.根据函数运算的结果进行排序
            reverse :是否是倒叙,True 倒叙 False 正序 
      
           l1 = [22, 33, 1, 2, 8, 7, 6, 5]
           l2 = sorted(l1)
           print(l1)#[22, 33, 1, 2, 8, 7, 6, 5]原列表不会改变
           print(l2)#[1, 2, 5, 6, 7, 8, 22, 33]
           #倒序:
           lst = [1,3,2,5,4]
           lst3 = sorted(lst,reverse=True)
           print(lst3) #[5, 4, 3, 2, 1]
      
          #字典使用sorted排序
          dic = {1:'a',3:'c',2:'b'}
          print(sorted(dic))   # 字典排序返回的就是排序后的key  [1, 2, 3]                                                        
      
           l2 = [('大壮', 76), ('雪飞', 70), ('纳钦', 94), ('张珵', 98), ('b哥',96)]
           print(sorted(l2))#[('b哥', 96), ('大壮', 76), ('张珵', 98), ('纳钦', 94), ('雪飞', 70)]
           print(sorted(l2,key= lambda x:x[1]))  # [('雪飞', 70), ('大壮', 76), ('纳钦', 94), ('b哥', 96), ('张珵', 98)]返回的是一个列表,默认从低到高
           print(sorted(l2,key= lambda x:x[1],reverse=True)) #[('张珵', 98), ('b哥', 96), ('纳钦', 94), ('大壮', 76), ('雪飞', 70)] 
      
           #和函数组合使用
          #定义一个列表,然后根据元素的长度排序
           lst = ['天龙八部', '西游记', '红楼梦', '三国演义']
          #计算字符串的长度
           def func(s):
               return len(s)
           print(sorted(lst, key=func))#['西游记', '红楼梦', '天龙八部', '三国演义']  
      
          #和lambda组合使用
           lst = ['天龙八部', '西游记', '红楼梦', '三国演义']
           print(sorted(lst, key=lambda s: len(s)))#['西游记', '红楼梦', '天龙八部', '三国演义']
      
           #按照年龄对学生信息进行排序
           lst = [{'id': 1, 'name': 'alex', 'age': 18},
                  {'id': 2, 'name': 'wusir', 'age': 17},
                  {'id': 3, 'name': 'taibai', 'age': 16}, ]
           print(sorted(lst, key=lambda e: e['age']))#[{'id': 3, 'name': 'taibai', 'age': 16}, {'id': 2, 'name': 'wusir', 'age': 17}, {'id': 1, 'name': 'alex', 'age': 18}] 
      
      
      # filter()筛选过滤 类似于列表推导式的筛选模式   返回的是迭代器
           语法: filter(function, iterable)
           function: 用来筛选的函数, 在filter中会自动的把iterable中的元素传递给function, 然后根据function返回的True或者False来判断是否保留此项数据
           iterable: 可迭代对象
      
           lst = [{'id': 1, 'name': 'alex', 'age': 18},
                  {'id': 1, 'name': 'wusir', 'age': 17},
                  {'id': 1, 'name': 'taibai', 'age': 16}, ]
           ls = filter(lambda e: e['age'] > 16, lst)   #返回的是迭代器
           print(list(ls))#转化成列表 [{'id': 1, 'name': 'alex', 'age': 18}, {'id': 1, 'name': 'wusir', 'age': 17}]
      
           #列表推导式的筛选模式                                                       
           l1 = [2, 3, 4, 1, 6, 7, 8]
           print([i for i in l1 if i > 3])  # 返回的是列表
      
           l1 = [2, 3, 4, 1, 6, 7, 8]
           ret = filter(lambda x: x > 3,l1)  # 返回的是迭代器
           print(ret)#<filter object at 0x00000165B06D7F28>
           print(list(ret))#[4, 6, 7, 8]
      
      # map() 映射函数  类似于列表推导式的循环模式  返回的是迭代器
           语法: map(function,iterable) 可以对可迭代对象中的每一个元素进映射,分别取出来执行function
      
           #列表推导式的循环模式
           print([i**2 for i in range(1,6)])  # 返回的是列表
           #[1, 4, 9, 16, 25]
      
           #计算每个元素的平方,返回新列表                                                   
           ret = map(lambda x: x**2,range(1,6))  # 返回的是迭代器
           print(ret)#<map object at 0x00000191237C7EB8>
           print(list(ret))#[1, 4, 9, 16, 25]
      
           # 计算两个列表中相同位置的数据的和
           lst1 = [1, 2, 3, 4, 5]
           lst2 = [2, 4, 6, 8, 10]
           print(list(map(lambda x, y: x+y, lst1, lst2)))#[3, 6, 9, 12, 15]                                                        
      
      # reduce
          # 在Python2.x版本中recude是直接 import就可以的, python3.x版本中需要从functools这个包中导入
          # reduce 的使用方式:reduce(函数名,可迭代对象)  # 这两个参数必须都要有,缺一个不行
      
          from functools import reduce
          def func(x,y):
              return x + y
          ret = reduce(func,[3,4,5,6,7])
          print(ret)  # 结果 25
      
          #普通函数版
          from functools import reduce
          def func(x,y):
              return x * 10 + y
          l = reduce(func,[1,2,3,4])
          print(l)#1234
          第一次的时候 x是1, y是2  x乘以10就是10,然后加上y也就是2最终结果是12然后临时存储起来了
          第二次的时候x是临时存储的值12 x乘以10就是 120 然后加上y也就是3最终结果是123临时存储起来了
          第三次的时候x是临时存储的值123 x乘以10就是 1230 然后加上y也就是4最终结果是1234然后返回了
      
          #匿名函数版
          from functools import reduce
          l = reduce(lambda x,y:x*10+y,[1,2,3,4])
          print(l)#1234
      
          from functools import reduce
          def func(x,y):
              return x + y
          l = reduce(func,[11,2,3,4])  #第一次的时候取2个数据,之后都取1个。
          print(l)
          '''
              第一次:x  y  : 11  2     x + y =     记录: 13
              第二次:x = 13   y  = 3    x +  y =   记录: 16
              第三次  x = 16   y = 4 .......
              '''
    3. 闭包:

      整个历史中的某个商品的平均收盘价。什么叫平局收盘价呢?就是从这个商品一出现开始,每天记录当天价格,然后计算他的平均值:平均值要考虑直至目前为止所有的价格。

      比如大众推出了一款新车:小白轿车。

      第一天价格为:100000元,平均收盘价:100000元

      第二天价格为:110000元,平均收盘价:(100000 + 110000)/2 元

      第三天价格为:120000元,平均收盘价:(100000 + 110000 + 120000)/3 元

    # 封闭的东西: 保证数据的安全。
    
    # 方案一:
     l1 = []  # 全局变量 数据不安全
     li = []
     def make_averager(new_value):
         l1.append(new_value)
         total = sum(l1)
         averager = total/len(l1)
         return averager
     print(make_averager(100000))
     print(make_averager(110000))
           .....(多行代码)
     l1.append(666)
     print(make_averager(120000))
     print(make_averager(90000))
    
    # 方案二: 数据安全,l1不能是全局变量。
    # 每次执行的时候,l1列表都会重新赋值成[]
     li = []
     def make_averager(new_value):
         l1 = []
         l1.append(new_value)
         total = sum(l1)
         averager = total/len(l1)
         return averager
     print(make_averager(100000))
     print(make_averager(110000))
            .....(多行代码)
     print(make_averager(120000))
     print(make_averager(90000))
    
    # 方案三: 闭包
     #在函数中嵌套了一个函数。avg 这个变量接收的实际是averager函数名,也就是其对应的内存地址,我执行了三次avg 也就是执行了三次averager这个函数。
    def make_averager():
        l1 = []
        def averager(new_value):
            l1.append(new_value)
            print(l1)
            total = sum(l1)
            return total/len(l1)
        return averager
     avg = make_averager()  # 【重点理解】返回值averager给avg  avg得到了内层函数的内存地址,所以外层函数执行完后,只要有内层函数的内存地址,下面的print语句依然可以执行内层函数
     print(avg(100000))
     print(avg(110000))
     print(avg(120000))
     print(avg(190000))
     ## 函数名.__code__.co_freevars 查看函数的自由变量
     print(avg.__code__.co_freevars)#('l1',)
     # 函数名.__code__.co_varnames 查看函数的局部变量
     print(avg.__code__.co_varnames)#('new_value', 'total')
     #获取具体的自由变量对象,也就是cell对象。
     print(avg.__closure__)#(<cell at 0x0000029744E374C8: list object at 0x0000029744ECE948>,)
     #cell_contents 自由变量具体的值
     print(avg.__closure__[0].cell_contents)#[]
    
    
    
    def func():
        return 666
    print(func)#<function func at 0x00000219A46C9AE8> 函数名指向函数的内存地址
    print(globals())#不包含 'ret': 666
    ret = func()
    print(globals())#包含  'ret': 666
    
     闭包: 多用于面试题: 什么是闭包? 闭包有什么作用。
    
    闭包的定义:
     1,闭包只能存在嵌套函数中。闭包是嵌套在函数中的函数
     2,闭包必须是内层函数对外层函数非全局变量的引用(使用),就会形成闭包。【使用:可改变  引用:直接使用,如print()】
    
     自由变量:被引用的非全局变量也称作自由变量,这个自由变量会与内层函数产生一个绑定关系,自由变量不会在内存中消失,而且全局还引用不到。
    
     闭包的作用:保证数据的安全。保存局部信息不被销毁,保证数据的安全性。
     闭包的应用:可以保存一些非全局变量但是不易被销毁、改变的数据。装饰器
    
    
    # 如何判断一个嵌套函数是不是闭包
    1,闭包只能存在嵌套函数中。
    2,内层函数对外层函数非全局变量的引用(使用),就会形成闭包。
    
    # 例1:是闭包
     def wrapper():
         a = 1     #a是自由变量
         def inner():
             print(a)
         return inner
     ret = wrapper()
    
    
    # 例2:也是闭包!【讲】
     def wrapper(a,b):   #传参相当于a=2,b=3,相当于在函数内重新定义变量,所以a,b都是外层函数的非全局变量,即a,b都是自由变量
         def inner():
             print(a)
             print(b)
         return inner
     a = 2
     b = 3
     ret = wrapper(a,b)
     print(ret.__code__.co_freevars)  # ('a', 'b')  #用几个就有几个自由变量
     print(ret.__closure__)#(<cell at 0x000001F3155274C8: int object at 0x00000000513A6C30>, <cell at 0x000001F3155274F8: int object at 0x00000000513A6C50>)
     print(ret.__closure__[0].cell_contents)# 2
     print(ret.__closure__[1].cell_contents)# 3
    
      #例3: 
      def wrapper():
          count = 1  # 不可变数据类型
          def inner():
              nonlocal count     #count是自由变量
              count += 1
          print(count)  # 1
          inner()
          print(count)  # 2
          return inner
      ret = wrapper()
      print(ret.__code__.co_freevars)#('count',)
    
    # 如何代码判断闭包?
    
    def make_averager():
        l1 = []   #l1是自由变量
        def averager(new_value):
            l1.append(new_value)
            print(l1)
            total = sum(l1)
            return total/len(l1)
        return averager
    
    avg = make_averager()  # averager
    print(avg.__code__.co_freevars)
  2. 总结

    • 匿名函数。

    • 内置函数。*** 一定要记住,敲3遍以上。 ** 尽量记住,2遍。

    • 闭包:多用于面试题: 什么是闭包? 闭包有什么作用。

相关文章