zoukankan      html  css  js  c++  java
  • python学习笔记 第五章 函数

    第五章 函数

    函数式编程:增加代码的可读性和重用性

    函数的基本格式

    def func():
        """
        函数是干什么的
        :param name:
        :param age:
        :return:
        """
        return None
    

    函数可以当参数,也可以做变量和返回值

    5.1自定义函数

    #方式一:
    def func():
        return 666
    
    #方式二:lambda表达式
    func = lambda : return 666
    

    5.2参数和返回值

    5.2.1基本的参数知识

    • 任意个数
    • 任意类型
    def func(a1,a2):
        print(a1,a2)
        
    func(1,"apple")
    
    • 形式参数和实际参数

    5.2.2位置传参

    根据参数的位置依次传递参数

    5.2.3 关键字传参

    def func(a1,a2):
        pass
    func(a2=6,a1=4)  #可以改变参数的位置
    

    5.2.4位置传参和关键字传参

    位置传参和关键字传参可以一起混合使用,但是需要满足位置传入的参数在前,关键字参数在后

    5.2.5默认参数

    采用默认参数则说明此参数可传可不传

    若不传递参数,则默认此参数的值为定义函数的时候的值。(注意:也需要满足位置参数>关键字参数的要求)

    注意:此处有坑

    5.2.6万能参数

    • *args

      • 可以接受任意个数的参数,并且将参数 转换成元组

        • 有*

          必须要传一个元组(列表、集合也可以,也会将其添加)

          def func(*args):
              print(args)
          
          #其实内部是将其循环添加到元组中
          func(*[11,2,3])  #(11, 2, 3)
          func(*{1,2,3})   #(1, 2, 3)
          
        • 无*

      • 只能用位置传参

    def func(*args):
        print(args)
        
    func(1,2) #args=(1,2)
    func((11,22,33)) #args=((11,22,33),)
    func(*(11,22,33)) #args=(11,22,33)
    

    *args与位置参数、关键字参数

    def func(a1, *args, a2):
        print(a1, args, a2)
    
    #func(1, 2, 3, 1, 3)  #报错:func() missing 1 required keyword-only argument: 'a2'
    func(1,2,3,1,a2=3) #1 (2, 3, 1) 3
    #虽然可以这样,但是并不推荐这样使用
    
    • **kwargs

      • 可以接受任意个数的参数,并且将参数转换成字典

        • 有*

          必须要传一个字典

        • 无*

      • 只能用关键字传参

    def func(**v1):
        print(v1)
    
    func(k1=1)  #{'k1': 1}
    #等式前面的作为key,后面的值作为value保存到字典中
    func(**{"k1":1,"k2":"apple"})  #{'k1': 1, 'k2': 'apple'}
    
    • *args 和 **kwargs

      def func(*args,**kwargs):
          print(args,kwargs)
      
      func(1,2,3,k1=4,k5=6,k6=666)  #(1, 2, 3) {'k1': 4, 'k5': 6, 'k6': 666}
      #func(k1=1,22,33,k6=88)  #报错:positional argument follows keyword argument
      func(*[1,2,3],**{"k1":1,"k2":"apple"})   #func(*[1,2,3],**{"k1":1,"k2":"apple"})
      func(111,222,*[1,2,3],k1=666,**{"k2":"888"})  #(111, 222, 1, 2, 3) {'k1': 666, 'k2': '888'}
      #记住位置参数传递给*args,关键字参数传递给**kwargs,且位置参数在关键字参数之前
      

    测试:

    #看代码写结果
    def func(*args,**kwargs):
        print(args,kwargs)
    
    func(12,3,*[11,22])  #有*会输出四个元素,没有*会输出三个元素
    #(12, 3, 11, 22) {}
    func(("alex","apple",),fruit="pear")
    #(('alex', 'apple'),) {'fruit': 'pear'}
    

    5.2.7参数的重点

    def func(a1,a2):
        pass
    
    def func1(a1,a2=8):
        pass
    
    def func2(*args,**kwargs):
    	pass
    
    #调用参数的时候,位置参数>关键字参数
    
    #函数的参数传递的是什么?
    """
    v=[11,22,33]
    def func(arg):
        print(id(arg))
    
    print(id(v)) #打印列表的内存地址
    func(v)  #传送的地址和上面的地址是一样的,代表函数的参数传递的是内存地址
    """
    

    5.2.8参数的补充

    参数的补充:函数的默认值慎重使用可变数据类型

    #如果想要给value设置默认是空列表
    
    #不推荐(坑)
    def func(data.value=[]):
        pass
    
    #推荐
    def func(data,value=None):
        if not value:
            value=[]
    
    def func(data,value=[]):
        value.append(data)
        return value
    
    v1=func(1)
    v2=func(1,[11,22,33])
    v3=func(2)
    print(v1,v2,v3)  #[1, 2] [11, 22, 33, 1] [1, 2]
    #可以发现v1和v3由于列表是可变数据类型,append方法添加以后才打印,所以v1=v3=[1,2]
    #v2是由于其自己有列表,不用默认的列表,所以没有产生影响
    
    #变形
    def func(a,b=[]):
        b.append(a)
        print(b)
    
    #添加完立即打印出结果
    func(1)   #[1]
    func(2,[11,22,33])  #[11,22,33,2]
    func(3)  #[1,3]
    

    5.3作用域

    python是以函数作为一个作用域的

    • 全局作用域
    • 局部作用域

    5.3.1作用域的规则

    • 优先在自己的作用域查找,自己没有就去父级-->父级-->直到全局,全局没有就报错

    • 父级拿不到子级得局部变量,子作用域中只能找到父级中的值,无法为父级的变量进行赋值

      在函数里面定义的属于自己的局部的作用域,对于字符串、布尔值、字符串等不可变的数据类型,赋值在全局中不会生效,只是在该作用域中再创建一个这样的值,而像列表等数据类型,可以修改,那么对应得全局变量也会发生变化。(子作用域只能读 或修改父级的值,不能重新赋值)

      NUM=[1,2,3]
      def func():
          NUM.append(666)  #修改
      func()
      print(NUM)  #[1,2,3,666]
      

    5.3.2函数的执行与作用域

    a=1
    def func():  #定义函数的时候不会执行,当调用此 函数的时候才会执行
        x1=666
        print(x1)
        a=6
        print(a)
        print(b)
    
    #func() #报错:name 'b' is not defined
    b=2  #在函数前定义了b,故可以在func函数中可以用b
    print(a)
    func()     #1,666,6,2
    print(a,b)  #1 2
    

    函数中调用另一个函数

    def s1():
        print("hello")
    
    def s2():
        print(s1)
    s2()   #<function s1 at 0x000001C8DDD32378>
    #发现s1其实是函数 的地址,在全局中定义的s1函数,s2函数可以在全局中找到
    
    

    5.3.3 global 和nonlocal

    global将对全局的变量进行赋值,nonlocal对父级的变量进行赋值

    一般情况下不会使用,这样会导致代码可读性差。

    #global 和 nonlocal
    
    name = "apple"
    def func():
        global name
        name="pear"
    
    func()
    print(name)  #pear
    
    name="apple"
    def func1():
        name="pear"
        def func2():
            nonlocal name
            name=666
        func2()
        print(name)
    
    func1()    #666
    print(name)   #apple
    

    5.3.4全局变量的使用

    由于之前都没有使用函数,没有全局变量的概念,并没有对全局变量提出要求

    但是 现在,出于专业性的考虑,需要将全局变量全部大写,以后一旦在函数中看到大写则可以认为此为全局变量

    USER_LIST=[11,2,3]   #规范,全局变量大写
    def func():
        name="aaa"
       
    def show():
        USER_LIST.append(123)
    

    5.4函数返回值

    默认return 会停止运行程序,并返回None。若程序有return的值,则返回对应的值

    #函数的返回值
    def func():
        pass
    v=func()
    print(v)  #None
    
    

    返回值的特殊情况

    def func():
        return 1,2,3
    v=func()
    print(v)  #(1, 2, 3)
    

    练习1:

    def func(arg):
        return arg.pop(1)
    
    result=func([11,22,33,44])
    print(result) #22
    

    练习2:

    def f1():
        print("f1")
        return f3()
    
    def f2():
        print("f2")
        return f1
    
    def f3():
        print("f3")
    
    func=f2()
    result=func()
    print(result)  #f2,f1,f3,None
    

    练习3:

    name="大佬"
    def func():
        def inner():
            print(name)
        return inner()
    
    v=func()
    print(v)  #大佬,None
    

    5.5函数的嵌套

    def func():
        name="apple"
        
        def func1():   #在小作用域创建的函数
            print(name)
        
        func1()    #只能在 此作用域内使用
        print(name)
    
    func()   #打印两次apple
    

    5.6函数的进阶

    5.6.1函数的赋值

    (1)函数名可以当作变量使用

    def func():
        print(123)
        
    V1=func
    func()  #123
    V1()    #123
    
    def func():
        print(123)
        
    FUNC_LIST=[func,func,func]
    FUNC_LIST[0]()  #123
    for i in FUNC_LIST:
        i() #执行三次输出123
        
    FUNC_SET={func,func,func}
    for i in FUNC_SET:
        i()  #执行一次输出123
    #集合中的元素不能重复,一般不会放函数进集合中
    
    #同理函数也可以放入元组和字典中
    def func():
        print(123)
    FUNC_DICT={func:"1"}   #函数可以作为字典的键,但是很少这样做
    for i in FUNC_DICT:
        i()   #123
    
    FUNC_DICT_NEW={"k1":func,"k2":func}
    FUNC_DICT_NEW["k1"]()  #123 
    

    容易混淆:

    def func():
        print(123)
    FUNC_LIST=[func,func,func]     #保存的是函数的内存地址
    FUNC_LIST_NEW=[func(),func(),func()]   #会执行函数,打印三次123,返回值为None
    
    print(FUNC_LIST_NEW)  #[None,None,None]
    

    (2)函数可以当作参数进行传递

    def func(arg):
        print(arg)
    
    func(1)
    func([1,2,3,4])
    
    def show():
        return 999
    func(show)
    
    def func(arg):
        arg()
    
    def show():
        print(666)
    func(show)  #666
    #函数执行过程:func函数以show为参数进入,遇到括号,执行show函数,打印666
    
    def func(arg):
        v1=arg()
        print(v1)
    
    def show():
        print(666)
    
    RESULT=func(show) #show为参数入func函数,执行show(),打印出666,返回值为None给v1,打印输出v1
    print(RESULT)  #RESULT为None
    #所以结果为 666 None None
    

    5.6.2lambda表达式

    也称为匿名函数

    #lambda 表达式解决简单函数的问题
    def func(a1,a2):
        return a1+100  #直接给返回值
    
    func1=lambda a1,a2:a1+100  #等价于func(),隐含着一个return 
    

    lambda表达式的 不同形式

    #lambda表达式的不同形式
    func1=lambda :100  #没有参数,返回值为100
    result1=func1()
    print(result1)  #100
    
    func2=lambda *args,**kwargs:len(args)+len(kwargs)
    result2=func2(1,2,3,a1=4,a2=5,a3=6)
    print(result2)  #6  返回传入的参数的个数
    
    #不能在lambda表达式创建变量
    DATA=100
    def func3():
        DATA=1000
        func4=lambda a1:a1+DATA  #此时的DATA在父级找,父级找不到才在全局找
        v=func4(1)
        print(v)
    
    func3()  #1001
    
    #lambda表达式的应用
    #比较两个数的大小,返回较大的那个值
    
    def func1(n1,n2):
        if n1>n2:
            return n1
        else:
            return n2
    
    func2=lambda n1,n2: n1 if n1>n2 else n2
    
    result1=func1(5,10)
    result2=func2(5,10)
    print(result1,result2)  #10 10
    
    

    lambda表达式的一些练习

    USER_LIST=[]
    def func1(x):
        v=USER_LIST.append(x)   #append方法有返回值,v接收返回值
        return v
    result1 = func1("apple")
    print(result1)  #None 返回值为空
    print(USER_LIST)  #['apple']
    
    def func2(x):
        v=x.strip()  #返回新的值
        return v
    result2=func2(" apple ")
    print(result2)  #apple  返回没有空白的
    
    #小结:列表的所有方法基本上都是返回None
    #字符串的方法基本上都是返回新的值
    
    USER_LIST=[]
    func3 = lambda x:USER_LIST.append(x)
    result3=func3("apple")
    print(result3)  #None 与func1()功能类似,返回的是append方法的值
    print(USER_LIST)  #['apple']   将字符串添加进列表中,与func1()结果相同
    
    func4=lambda x:x.split("l")
    result4=func4("apple")
    print(result4)  #['app','le'] 得到的是split()划分以后的结果(列表),并返回func4
    
    func_list=[lambda x:x.strip(),lambda y:y+1999,lambda x,y:x+y]
    result5=func_list[0](" apple ")
    print(result5)   #apple 返回去除空白的值
    
    

    5.7内置函数

    python的内置函数

    Built-in Functions
    abs() dict() help() min() setattr()
    all() dir() hex() next() slice()
    any() divmod() id() object() sorted()
    ascii() enumerate() input() oct() staticmethod()
    bin() eval() int() open() str()
    bool() exec() isinstance() ord() sum()
    bytearray() filter() issubclass() pow() super()
    bytes() float(0 iter() print() tuple()
    callable() format() len() property() type()
    chr() forzenset() list() range() vars()
    classmethod getattr() locals() repr() zip()
    compile() globals() map() reversed() import()
    complex() hasattr() max() round()
    delattr() hash() memoryview() set()

    5.7.1内置函数的分类

    • len

    • open

    • range

    • id 找内存地址

    • type

    • 输入和输出: input print

    • 强制转换:bool str int list tuple dict set

    • 进制转换相关的

      • bin,将十进制转换成二进制

      • oct,将十进制转化为八进制

      • int,将其他进制转换成十进制

        #int 作为一个中介,可以进行其他进制与其他进制之间的转换
        #int的默认参数base是10
        
        #1.二进制转换成十进制
        v1="0b1101"  #字符串
        result=int(v1,base=2) #将二进制转换成十进制
        result2=bin(result) #十进制转换成二进制
        
        #2.八进制转换成十进制
        v2="0o1101"
        result3=int(v2,base=8)
        #3.十六进制转换成十进制
        v3="0x1101"
        result4=int(v3,base=16)
        
      • hex,将十进制转换成十六进制

    • 数学相关的

      • abs() 取绝对值

        v=abs(-1)
        print(v)   #1 返回绝对值
        
      • float() 转换成浮点类型(小数)

        v=float(55)
        print(v)  #55.0  
        
      • int() 转换 成整数

        v=int(55.5)
        print(v)  #55 保留整数部分
        
      • max() 找到最大的值

        v=[1,2,3,666]
        result=max(v)
        print(result)  #666 注意内置函数和列表的方法的使用不同
        
      • sum() 求和

        v=[1,2,3,4]
        result=sum(v)
        print(result)  #10
        
      • divmod() 返回两个值,前面返回商,后面返回余数

        v=1001
        result=divmod(1001,5)
        print(result)  #(200,1)  前面返回商,后面返回余数
        a,b=divmod(1001,5)
        print(a,b)  #200 1
        
      • pow() 指数函数

        result1=2**3   #2的3次方
        reulut2=pow(2,3) #用传参的方式计算指数
        print(result1,result2) #8,8
        
        
      • round() 保留几位小数,并且还能四舍五入

        result=round(1.2567,2)
        print(result)  #1.26
        

    5.7.2内置函数的练习

    USER_LIST=[]
    for i in range(1,888):
        temp={"name":"hello %s"%i,"email":"123%s.qq.com"%i}
        USER_LIST.append(temp)
    
    #请通过分页对于以上数据进行展示
    #要求:每页输入10条数据,让用户输入要查看的页面:页码
    
    #分析:对于现在的USER_LIST已经有了数据,需要判断数据的长度
    #数据总长度
    total_count=len(USER_LIST)
    
    #每页显示十条数据
    per_page_count=10
    
    #总页码
    max_page_num,a=divmod(total_count,per_page_count)  #max_page为最大的页码数,a 为余数
    
    num=input("请输入需要查看的页码:")
    choice=int(num)
    if choice<=max_page_num+1 and choice>0:
        print("输入合法")
        start=(choice-1)*per_page_count
        end=choice*per_page_count
        data=USER_LIST[start:end]
        for i in data:
            print(i)
    else:
        print("输入不合法,必须是 1 - %s"%(max_page_num))
    
    #第一页:USER_LIST[0:10] ->0123456789
    #第二页:...
    
    

    5.7.3强化补充

    #1字节等于八位
    #ip=192.168.12.79 ->转换成四个点分的二进制
    
    ip="192.168.12.79"
    data=ip.split(".")
    result_list=[]
    for i in data:
        result_list.append(bin(int(i)))
    print(",".join(result_list))  #0b11000000,0b10101000,0b1100,0b1001111
    
    #拼接起来转换成一个整的二进制,再转换成十进制
    #注意两个地方:1.需要将二进制的位数补足八位,总共是三十二位的二进制2.要将0b去掉
    fin_result=""
    for i in result_list:
        new_data=i.split("0b")  #去掉0b
        if len(new_data[1])<8:   #判断如果二进制的位数小于八位,则在其前面补上足够的0
            zero_num=8-len(new_data[1])
            for i in range(0,zero_num):
                new_data[1]="0"+new_data[1]
        fin_result=fin_result+new_data[1]
    print(fin_result)
    print(int(fin_result,base=2))
    

    5.7.4编码相关

    • chr (def chr(code:int) -> str) 将十进制数字转换成unicode 编码中的对应的字符串

      v1=chr(65)
      print(v1)  #A
      
      v2=chr(10000)
      print(v2)   #✐
      
    • ord 将字符串转换成unicode编码的十进制数字

      v="中国"
      for item in v:
          data=ord(item)
          print(data)
      #20013 22269
      #再用bin就可以将其十进制数转换为二进制数
      

    小案例:生成随机验证码

    import random
    
    def get_random_code(length=6):
        data=[]
        for i in range(length):
            v=random.randint(65,90)  #生成一个范围内的随机数
            data.append(chr(v))
        return "".join(data)
    
    code =get_random_code()
    print(code)
    

    5.7.5内置高级函数

    • map,遍历序列,对序列中每个元素进行操作,最终获取新的序列

      v1=[11,22,33,44]
      #要求:将列表中的每一个元素都进行加100
      for i in range(0,len(v1)):
          v1[i]=v1[i]+100
      print(v1) #[111, 122, 133, 144]
      
      def func(arg):
          return arg+100
      result=map(func,v1)  #将函数的返回值添加到返回值[]
      print(list(result))  #[211, 222, 233, 244]
      
      result1=map(lambda x:x+1000,v1) #py2会直接返回列表,但是py3为了节省内存,只返回一个特殊的值
      print(list(result1))  #[1111, 1122, 1133, 1144]
      #发现此时用的V1是没用第一个map函数之前的结果
      #这是由于map有返回值,不影响v1
      
      #map的第一个参数:必须是一个函数
      #map的第二个参数:必须是可以迭代的类型(可以被for循环)
      
    • filter,对序列中的元素进行筛选,最终获取符合条件的序列

      v1=[11,22,33,"as",44,"ds"]
      def func(x):
          if type(x)==int:
              return True
          return False
      result=filter(func,v1) #生成一个列表,若函数返回True,则将其值放入到列表中,返回False则不放入
      print(list(result))  #[11, 22, 33, 44]
      
      #result1=filter(lambda x:True if type(x)==int else False,v1)
      #print(list(result1))  #[11, 22, 33, 44]
      
      result1=filter(lambda x:type(x)==int,v1)
      print(list(result1))  #[11, 22, 33, 44]
      
    • reduce,对序列内所有元素进行累计操作

      import functools #py3中内置函数已经没有reduce
      v1=[1,2,3,4,5,6]
      def func(x,y):
          return x+y
      result=functools.reduce(func,v1)
      print(result)  #进行累加输出结果21
      
      #改用lambda表达式
      result2=functools.reduce(lambda x,y:x+y,v1)
      print(result)  #21
      

    小结:

    ​ 1.函数可以当作是一个变量:参数传值/当元素嵌套到字典中

    ​ 2.lambda表达式

    ​ 3.内置函数

    5.8函数的中高级

    • 函数的中高级(闭包和高阶函数)
    • 内置函数
    • 内置模块(.py文件)
    #第一题
    for item in range():
        pass
    print(item)  #9
    
    #第二题
    def func():
        for item in range(10):
            pass
        print(item)
    func()  #执行函数之后item值为9
    
    #第三题
    item = 10
    def func():
        item = 2
        def inner():
            print(item)
        for item in range(10):
            pass   #item的值修改为9
        inner()
    func()   #9
    
    
    #第四题
    def func():
        for num in range(10):
            pass
        v4=[lambda:num+10,lambda:num+100,lambda:num+100,]
        result1=v4[1]()
        num=66
        result2=v4[2]()
        print(result1,result2)
    func()   #109 , 166
    
    
    

    补充:

    1.数据类型中的函数到底有没有返回值?

    • 无返回值

      v=[11,22,33]
      v.append()  #列表的方法一般没有返回值
      
    • 有返回值

      v="alex"
      result=v.split("l")   #字符串的方法大部分有返回值,且split返回的是列表,其他的strip/replace等返回字符串
      
      v={"k1":"v2"}
      result1=v.get("k1")
      result2=v.keys()   #字典的方法中keys()/values()/items()都是有返回值的
      
    • 有返回值+修改数据

      v=[11,22,33]
      resut=v.pop()  #返回修改的值
      

      常用的需要记住的

      • str

        • strip,返回字符串
        • split,返回列表
        • replace,返回字符串
        • upper,返回字符串
        • join,返回字符串
      • list

        • append,无返回值
        • insert,无返回值
        • pop,返回要删除的数据
        • remove,无
        • find/index,返回索引的值
      • dict

        • keys(),返回列表

        • values(),返回列表

        • items(),返回字典

          v={"k1":"v1","k2":"v2"}
          result=v.items()
          print(result)   #dict_items([('k1', 'v1'), ('k2', 'v2')])
          

    5.8.1函数可以做返回值

    先看一段代码分析结果:

    def func(arg):
        return arg.replace("猪头","**")
    
    def run():
        msg="我看你像一个猪头"
        result=func(msg)
        print(result)
        
    data=run()   #先执行run函数,打印出result"我看你像一个**",然后函数run没有返回值,返回None给data
    print(data)  #data输出为None
    

    再看一段代码

    DATA_LIST=[]
    
    def func(arg):
        #return DATA_LIST.insert(0,arg)
        DATA_LIST.insert(0,arg)
        return None
    
    data=func("绕不死你")
    print(data)  #None
    print(DATA_LIST)  #["绕不死你"]
    

    再次强调:函数不被调用,内部的代码永远不会执行

    func_list=[]
    for i in range(10):
        func_list.append(lambda :i)
    result=func_list[0]()
    print(result)   #9
    

    练习:

    func_list=[]
    
    for i in range(10):
        func_list.append(lambda x:x+i)
    
    for i in range(0,len(func_list)):
        result=func_list[i](i)
        print(result)  #0,2,4,6,8,10,12,14,16,18
    

    5.8.2闭包

    闭包的概念:为函数创建一块区域,并为其维护自己的数据,为以后执行时方便调用

    闭包的应用场景:装饰器/SQL Alchemy源码中

    def func(name):
        def inner():
            print(name)
        return inner   #返回的是嵌套函数的函数名
    v1=func("alex")  #保留嵌套函数的函数名,以便为后面函数运行的时候提供数据
    v1()  
    v2=func("eric")
    v2()
    
    • 函数内部执行相互之间不会混乱
    • 执行完毕+内部元素不被其他变量使用的时候 => 销毁
    def func():
        print(123)
    
    def bar():
        return func
    
    v=bar()  #v保存bar函数的返回值func
    v()  #v一加括号就可以运行,打印出123
    
    def bar():
        def inner():
            print(123)
        return inner
    v=bar()  #返回值为inner,故bar函数里面的inner还在被使用,故bar函数不会被销毁
    v()  #找到inner函数执行
    
    name="apple"
    def bar():
        name="cherry"
        def inner():
            print(name)
        return inner
    v=bar()  #执行bar函数,返回inner
    v()     #执行inner函数,发现其没有name这个变量,故其到父级去找name,父级的name为cherry,打印出cherry
    
    
    name="fruit"
    def bar(name):
        def inner():
            print(name)
        return inner
    v1=bar("apple")  #{name=apple,inner} 闭包,为函数创建一块区域(内部变量供字节使用,为以后函数的执行提供数据)
    v2=bar("cherry") #{name=cherry,inner}
    v1()
    v2()
    

    练习题:

    #第一题
    name="alex"
    def base():
        print(name)
    
    def func():
        name="eric"
        base()  #base()和func()都是由全局创建的,func函数执行到此相当于直接到base函数中创建一块内存空间
    
    func()  #alex
    
    #第二题
    name="alex"
    def func():
        name="eric"
        def base():
            print(name)
        base()  
    
    func()  #eric
    
    #第三题
    name="alex"
    def func():
        name="eric"
        def base():
            print(name)
        return base
    
    base=func()
    base()  #eric
    
    

    注意:函数在何时被谁创建?

    面试题:

    #第一题
    info = []
    def func():
        print(item)
    
    for item in range(10):
        info.append(func)   #循环不会创建作用域
    
    info[0]()  #9
    
    #第二题
    info = []
    def func(i):
        def inner():
            print(i)
        return inner
    
    for item in range(10):
        info.append(func(item))
    
    info[0]()  #0
    
    

    回顾:函数执行时,会创建一块内存保存自己函数执行的信息->闭包

    def base(arg):
        return arg
    
    
    def func(arg):
        def inner():
            return arg
    
        return inner
    
    
    base_list = []
    func_list = []
    
    for i in range(10):
        base_list.append(base)
        func_list.append(func(i))
    
    # 1.base_list和func_list中保存的是什么?
    # base_list中存储的是base函数
    # func_list中存储的是inner函数,特别是每个inner是在不同的地址创建,每次循环中传入的arg不同
    
    # 2.如果循环打印什么?
    for item in base_list:
        v = item(i)   #此时必须要传入参数,不然会报错
        print(v)  # 打印出的全部都是9
    
    for item in func_list:
        v = item()
        print(v)  # 打印出的是0-9
    

    含lambda表达式的闭包

    def func(name):
        return lambda x:x+name
    
    v1=func(1)
    v2=func(2)
    result1=v1(10)
    result2=v2(100)
    print(result1,result2) #11,102
    

    区分闭包和不是闭包的区别

    #不是闭包
    def func1(name):
        def inner():
            return 123
        return inner
    
    #是闭包:封装值+内层函数需要使用
    def func2(bane):
        def inner():
            print(name)
            return 123
        return inner
    

    5.8.3高阶函数

    • 把函数当作参数进行传递
    • 把函数当作返回值

    注意:队函数进行赋值

    5.9装饰器

    5.9.1装饰器原理

    先看一段代码

    v=1
    v=2
    # ##########################
    def func():
        pass
    v=10
    v=func
    
    # ##########################
    def base():
        print(1)
    def bar():
        print(2)
    
    bar=base
    bar()   #打印出的是1
    
    def func(arg):
        def inner():
            return arg()
        return inner
    
    def f1():
        print(123)
        return 666
    
    v1=func(f1)  #返回的是inner函数
    result=v1()  #执行inner(),再执行f1(),打印123,返回的是f1()的返回值666
    print(result)  #打印666
    
    

    =装饰器============

    def func(arg):
    	def  inner():
            returm arg()
        return inner
    
    def index():
        print(123)
        return 666
    
    #示例一:
    v1=index()  #执行index函数,打印123,并返回666
    
    #示例二:
    v2=func(index)  #v2是inner函数,arg=index
    index=666  #index被修改为666,但是arg仍保留原来index函数的地址
    v3=v2()  #执行inner函数,执行index(),打印666,返回123
    
    #示例三:
    v4=func(index)
    index=v4   #将inner函数的地址给index
    index()  #此时执行的是inner() arg=index
    

    5.9.2装饰器示例

    def func(arg):
        def inner():
            print("before")
            v=arg()
            print("after")
            return v
    	return inner
    #第一步:执行func函数并将下面的函数参数传递,相当于:func(index)
    #第二步:将fun的返回值重新赋值给下面的函数名:index=func(index)
    @func
    def index():
        print(123)
        return 666
    
    index()  #先打印before,再打印123,最后打印after
            
    

    5.9.3装饰器编写和应用

    #装饰器的编写
    def x(func):
        def y():
            ret=func()
            return  ret
        return y
    
    #装饰器的应用
    @x
    def index():
        pass
    
    #执行函数,自动触发装饰器
    v=index()
    print(v)
    

    记住:装饰器的编写格式:

    def 外层函数(参数):
        def 内层函数(*args,**kwargs):
            return 参数(*args,**kwargs)
        return 内层函数
    

    装饰器的应用格式:

    @外层函数
    def index():
        pass
    
    index()
    

    问:为什么要加*args **kwargs

    答:传入万能参数,使得装饰器在应用的时候可以接收不一样个数参数的函数,而不用写多个装饰器

    • 理解:

      • 变量赋值

        def func():
            print(i)
            
        v1=func
        func=666
        
      • 看看return的到底是什么

      • 自己>上级作用域

    5.9.4带参数的装饰器及其返回值

    装饰器的内层函数的参数选哟和原来的函数的参数统一,目的是为了给index传参

    所以建议用万能参数,使用一个万能参数的装饰器就可以满足全部的需求,

    同样,对于其返回值来说也是如此

    def x1(func):
        def inner(*args,**kwargs):
            return func(*args.**kwargs)
        return inner
    
    @x1
    def f1():
        print(123)
        
    v1=f1()
    
    def x1(func):
        def inner(*args,**kwargs):
           data=func(*args,**kwargs)
        return inner
           
    @x1
    def f1():
        print(123)
        return 666
     
    v1=f1()
    print(v1)   #None
    #inner函数执行之后没有返回值,故返回None
    

    装饰器建议的写法:

    def x1(func):
        def inner(*args,**kwargs):
            data=func(*args,**kwargs)
            return data
        return inner
    

    =带参数的装饰器=========

    #原来的装饰器:1.执行ret=xxx(index) 2.将返回值赋值给index=ret
    @xxx
    def index():
        pass
    
    #带参数的装饰器:第一步,执行v1=uuu(9)
    #第二步:ret=v1(index)
    #第三步:index=ret
    @uuu(9)  #先执行函数得到返回值再当作原来的装饰器,但是其传入一个参数可以进行更多的操作
    def index():
        pass
    
    
    def x(counter):
        def wrapper(func):
            def inner(*args,**kwargs):
                data=func(*args,**kwargs)
                return data
            return inner
        return wrapper
    
    @x(9)  #等价于执行wrapper=x(9),多传入参数9
    def index():
        pass
    
    #即使没有调用index函数,x(9)仍然会被执行,且在装饰器写@x(9)的时候就会被执行
    #装饰器生成的时候x函数和wrapper函数都会被执行,inner函数不会被执行
    
    

    应用:当需要不同的装饰器的时候,可以写成一个装饰器

    def x(counter):
        def wrapper(func):
            def inner(*args,**kwargs):
                if counter==False:
                    pass
                else:
                    pass
                data=func(*args,**kwargs)
                return data
            return inner
        return wrapper
    
    @x(True)
    def func1():
        pass
    
    @x(Flase)
    def func2():
        pass
    
    

    对于写缓存的时候会有应用,对于缓存的存活时间控制

    5.9.5关于函数执行的前后

    def x1(func):
        def inner(*args,**kwargs):
            print("调用原函数之前")
            data=func(*args,**kwargs)  #执行原函数并给出返回值
            print("调用原函数之后")
            return data
        return inner
    
    

    示例/:

    给一个读取文件的函数添加装饰器,使得其在执行函数前先判断路径是否存在

    #检查路径是否存在
    import os
    def wrapper(func):
        def inner(*args,**kwargs):
            #传入的位置参数在args[]中可以找到
            path=args[0]
            if not os.path.exists(path):
                print("路径不存在")
                return  None
            result=func(*args,**kwargs)
            return result
        return inner
    
    @wrapper
    def read_userinfo(path):
        file_obj=open(path,mode="r",encoding="utf-8")
        data=file_obj.read()
        file_obj.close()
        return data
    
    content=read_userinfo("/usr/bin")
    
    ##练习:请为下面所有函数编写一个装饰器,添加上装饰器以后可以实现:将装饰的函数执行5次,讲每次执行函数的结果按照##顺序放到列表中,最终返回列表
    import random
    def wrapper(func):
        def inner(*args,**kwargs):
            data=[]
            for i in range(5):
                result=func(*args,**kwargs)
                data.append(result)
            return data
        return inner
    
    @wrapper
    def func():
        return random.randint(1,4)
    
    result=func()  #执行五次,并将每次执行的结果追加到列表中 ,最终返回给result
    print(result)
    

    5.9.6元数据:Flask框架

    5.9.7多个装饰器:Flask框架

    @x1
    @x2
    def func():
        pass
    

    5.10递归

    def func():
        print(1)
        func()
    func()  #不断递归直到递归次数达到上限
    
    def func(1):
        print(1)
        func(i+1)
    func(1)
    
    #递归形成斐波那契数列
    def func(a,b):
        print(b)
        func(b,a+b)
    
    func(0,1)
    
    def func(a):
        if a==5:
            return 10000
        result=func(a+1)+10
        return result
    
    v=func(1) 
    print(v)  #10040
    

    练习:

    #找到400万内斐波那契最大的数
    """
    """
    num1=0
    num2=1
    count=0
    while num2<4000000:
        print(num2)
        num1,num2=num2,num1+num2
        count+=1
        
    print(num1,count)
    
  • 相关阅读:
    JVM调优之优化延迟
    Datagridview列自适应宽度和数据居中显示
    C# winform格式化Json
    Winform将select数据写入datagridview
    .NET使用NPOI从datagridview导出excel
    理解大数据
    ORACLE_BASE和ORACLE_HOME的区别
    tabpage平分tabcontrol
    WinForm设置主窗体为固定大小(禁止调整大小)
    加Application.DoEvents可以防止界面“未响应”
  • 原文地址:https://www.cnblogs.com/wrrr/p/13915553.html
Copyright © 2011-2022 走看看