• python第五章函数


    第五章 函数

    5.1三元运算/三目运算

    v = 前面  if 条件语句  else   后面
    #如果条件成立,"前面"赋值给v,否则后面赋值给v.
    v = a if a>b  else b  # 取a和b中值较大的赋值给v
    
    # 让用户输入值,如果值是整数,则转换成整数,否则赋值为None
    
    data = input('请输入值:')
    value =  int(data) if data.isdecimal() else None 
    

    5.2 函数

    5.2.1.函数介绍

    1. 截止目前为止,都是面向过程式编程.可读性差,重复性高,容易出错.

    2. 对于函数编程:

      • 本质:将N行代码拿到别处并给他起个名字,以后通过名字就可以找到这段代码并执行。
      • 场景:
        • 代码重复执行。
        • 代码量特别多超过一屏,可以选择通过函数进行代码的分割。
    3. 函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段。

      函数能提高应用的模块性,和代码的重复利用率.

      py3中给我们提供了许多内建函数,如len()/print()等等,我们也可以自定义函数,这叫做用户自定义函数 .

    5.2.2.函数定义和表达

    1. 定义如下:

      • 函数代码块以 def 关键词开头,后接函数标识符名称和圆括号 ()

      • 任何传入参数和自变量必须放在圆括号中间,圆括号之间可以用于定义参数。

      • 函数的第一行语句可以选择性地使用文档字符串—用于存放函数说明。

      • 函数内容以冒号起始,并且缩进。

      • return [表达式] 结束函数,选择性地返回一个值给调用方。不带表达式的return相当于返回 None。

        注意: 遇到return语句,后面的代码不执行.

    2. Python 定义函数使用 def 关键字,一般格式如下:

      def 函数名称(形参): #算列表中所有元素的和,括号中可以添加形式参数.简称形参,也可以不加.
          函数代码
      
      • 最简单的形式

        def hello() :
           print("Hello World!")  #定义函数
        
        hello()  # 调用函数,输出"Hello World!"
        
        
      • 复杂一些,加上参数

        #  计算列表中的元素的和
        def sum_list_element(list1):
            sum = 0
            for i in list1:
                sum += 1
             print(sum)
            
        #  调用函数
        sum_list_element([1,2,3,4,5,6,7,8,9])  # 输出45
                
        
        
      • 加上return的应用(重点) --> 返回多个值自动装换为元组

        # 比较2个数的大小,并返回得到较大的数
        def compare_num(a,b):
            v = a if a > b else b
            return v   # 如果没有return语句,  print(compare_num(5,10)) 输出的是None
        print(compare_num(5,10))   # 调用函数,得到a,b中较大的数,并打印出来.
        
        
        #函数没有返回值时,默认返回None
        #函数有返回值时,语句为:return 返回值.返回值可以是任意东西.
        def compare_num(a,b):
            return a if a>b else b  #和三目运算一起,返回a和b中较大的数.
        #############################################
        #  函数执行到return 语句,就返回,后面的语句不执行.
        #  若返回值为多个,默认将其添加到元组中,返回一个元组.
        def func(a,b,c,d)
        	return a,b,c,d
        
        v = func(1,'韩梅梅',[11,22,33,44,55],{'k1':'v1'})
        print(v)            # (1,'韩梅梅',[11,22,33,44,55],{'k1':'v1'})  元组,
        

    5.2.3函数参数解析

    1. 参数

      def func(a1,a2):
          函数体(可调用a1和a2)
          return 返回值
      # 严格按照顺序传参数:位置方式传参。
      # 实际参数可以是任意类型。
      
      def check_age(age):  #只有1个参数:age,参数数量可以是无穷多个.
          if age >= 18:
              print('你是成年人')
          else:
              print('你是未成年人')
              
      check_age(18)    #调用函数,输出你是成年人.
      
      
    2. 位置参数

      def func(a1,a2,a3,a4)
      	print(a1,a2,a3,a4)
        
      func(1,2,3,4)
      # 严格按顺序输入参数,顺序是固定的.
      
    3. 关键字传参

      def func(a1,a2)
      	print(a1,a2)
        
      func(a1 = 1 ,a2 = 2) 
      func(a2 = 2,a1 = 1)  # 俩者完全一样,全是关键字可以打乱顺序.
      
    4. 位置参数和关键字传参混用

      ######  这时必须位置参数在前,关键字参数在后
      def func(a1,a2,a3,a4)
      	print(a1,a2,a3,a4)
         
      func(1,10,a3 = 15,a4 = 88) 
      func(1, 10, a4=15, a3=88)  # 俩者等价,正确.
      func(a1=1,a2=2,a3=3,a4=4)  #正确
      func(a1=1,a2=2,15,a4 = 88)  # 错误
      func(1,2,a3 = 15,88)  #错误
      #################################
      #    必须位置参数在前,关键字参数在后, 位置参数 > 关键字参数  #
      
      
    5. 默认参数

      def func(a1,a2,a3=9,a4=10):   #  默认a3=9,a4=10,这时可以不输入a3 和 a4 参数.默认值为 9 和 10 
          print(a1,a2,a3,a4)
      
      func(11,22)   #正确
      func(11,22,10)  #  正确,修改默认参数a3 = 10 ,参数a4不输入.默认为10 .
      func(11,22,10,100)  #正确
      func(11,22,10,a4=100)   #正确
      func(11,22,a3=10,a4=100)    #正确
      func(11,a2=22,a3=10,a4=100)   #正确
      func(a1=11,a2=22,a3=10,a4=100)    #正确
      
      
    6. 万能参数(重点)

      • args(打散)可以接受任意个数的位置参数,并将参数转换成元组。

        • 没有调用函数 * 字符

          def func(*args):
              print(args)
          func(1,2,3,True,[11,22,33,44])
          #  输出为(1,2,3,True,[11,22,33,44])  元组
          func(*(1,2,3,4,5)) # 如果不加*号,函数会将序列当成一个元素加入到元组中,*相当于拆包.
          
        • 有调用函数 * 字符

          def func(*args):
              print(args)
          func(*(1,2,3,True,[11,22,33,44]))    
          #  输出为(1,2,3,True,[11,22,33,44])  元组
          
      • *args 只能用位置传参

        def func4(*args):
            print(args)
            
        func4(1)    元组(1,)
        func4(1,2)   元组(1,2)
        
        func4(1,2)
        func4(1,2)
        
        
      • **kwags(打散) 可以接受任意个数的关键字参数,并将参数转换成字典。

        • 没有调用函数 ** 字符

          def func(**kwargs):   
              print(kwargs)
          
          func(k1=1,k2="alex")
          
        • 有调用函数 ** 字符

          def func(**kwargs):
              print(kwargs)
          func(**{'k1':'v2','k2':'v2'}) # kwargs={'k1':'v2','k2':'v2'}func(*(1,2,3,4,5)) # 如果不加**号,函数会将序列当成一个元素加入到元组中,相当于只有键没没有值,就会报错.
          
        • **kwags(打散)只能用关键字传参

    5.2.4函数参数默认值使用可变类型--->有坑(重点)

    1. 补充:对于函数的默认值慎用可变类型。
    # 如果要想给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) # [1,]
    v2 = func(1,[11,22,33]) # [11,22,33,1]
    
    • 原因

      def func(data,value=[]): 
          value.append(data)
          return value 
      
      v1 = func(1) # [1,]     # 调用函数,作用域得到value=[],添加value=[1,]
      v2 = func(2)  # [1,2,]   #调用函数,value=[1,]再次添加元素2,
      
      v2 = func(1,[11,22,33]) # [11,22,33,1]
      
      ##############    def func(a,b=[]) 有什么陷阱?   #######
      答: Python函数在定义的时候。默认参数b的值就被计算出来了,即[],因为默认参数b也是一个变量,它指向对象即[],每次调用这个函数,如果改变b的内容每次调用时候默认参数也就改变了,不在是定义时候的[]了.应该换成None  .
      
      

    5.2.5函数参数混用

    def func(*args,**kwargs):
        print(args,kwargs)
    
    # func(1,2,3,4,5,k1=2,k5=9,k19=999)
    func(*[1,2,3],k1=2,k5=9,k19=999)
    func(*[1,2,3],**{'k1':1,'k2':3})
    func(111,222,*[1,2,3],k11='alex',**{'k1':1,'k2':3})
    
    

    5.2.6函数作用域

    1. 函数的作业域

      • 作用于全局,对任意一个py文件来说,全局作用域

      • 对函数来说:局部作用域

        #  在函数中定义的值,只在局部作用域中
        #  在全局作用域中找不到#
        a = 1
        b = 2
        def func():
            a = 10
            b = 20
            print(a) 
            print(b)
        func()     #  输出10  ,20
        print(a)
        print(b)   #输出 1    , 2
        
        
        
    2. 作用域查找数据规则::优先在自己的作用域找数据,自己没有就去 "父级" -> "父级" -> 直到全局,全部么有就报错。

      a = b = 1
      def func():
          b = 5
          print(a,b)
      func()     #  1 ,5
      print(a,b)  #   1, 1
      
    3. 子作用域只能找到父级作用域中的变量的值,不能重新为赋值父级作用域的变量赋值.

      • 例外,特别: global 变量名,强制把全局的变量赋值

        a = b = 1
        def func():
        	global b
            b = 5     # 更改全局变量b = 5
            print(a,b)
        func()     #  1 ,5
        print(a,b)  #   1, 5
        
      • nonlocal ,强制把父级的变量赋值 ,一级一级向上找寻,不找全局域.找不到则报错.

        a = b = 1
        def func():
        	nonlocal b
            b = 5     # 更改父级变量,如果找不到,再到父级的父级找寻,一直找到全局域之前(不包含全局域)
            print(a,b)
        func()      #会报错,父级就是全局域,nonlocal不包含全局域,故会报错,找不到b 
        print(a,b)  
        
        a = b = 1
        def func():
            a = 3
            b = 99
            print(a,b)
            def func1():
                nonlocal b
                b = 88
                print(a,b)
            func1()
        func()
        print(a,b)
        
        
      • 补充: 全局变量大写

    4. 递归函数(效率低下,不推荐)

      # 递归的返回值
      ##函数在内部调用自己--->  递归函数
      # 效率很低,python对栈,即函数递归的次数有限制-->1000次
      # 尽量不要使用 递归函数
      # 递归的返回值
      def func(a):
          if a == 5:
              return 100000
          result = func(a+1) + 10
      
      v = func(1)
      name = 'alex'
      def func():
          def inner():
              print(name)
           return inner
      v =func()
      
      def func(i):
          print(i)
          func(i+1)
          
      func(1)
      
      
      递归次数有限制 1000次
      

    5.2.7执行函数

    • 函数不被调用,内部代码永远不执行。

      def func():
          return i
      func_list = []
      for i in range(10):
          func_list.append(func)
      
      print(i) # 9
      v1 = func_list[4]()
      v2 = func_list[0]()
      
      func_list = []
      for i in range(10):
          # func_list.append(lambda :x) # 函数不被调用,内部永远不执行(不知道是什么。)
          func_list.append(lambda :i) # 函数不被调用,内部永远不执行(不知道是什么。)
      
      print(func_list)
      
      func_list[2]()=
      
      • 执行函数时,会新创建一块内存保存自己函数执行的信息 => 闭包

        def base():
            return i 
        
        def func(arg):
            def inner():
                return arg
            return inner
        
        base_list = [] # [base,base,]
        func_list = [] # [由第一次执行func函数的内存地址,内部arg=0 创建的inner函数,有arg=1的inner函数 ]
        for i in range(10): # i = 0 ,1
            base_list.append(base)
            func_list.append(func(i))
            
        # 1. base_list 和 func_list中分别保存的是什么?
        """
        base_list中存储都是base函数。
        func_list中存储的是inner函数,特别要说的是每个inner是在不同的地址创建。
        """
        # 2. 如果循环打印什么?
        for item in base_list:
        	v = item() # 执行base函数
            print(v) # 都是9
        for data in func_list:
            v = data()
            print(v) # 0 1 2 3 4 
        

    总结:

    • 传参:位置参数 > 关键字参数
    • 函数不被调用,内部代码永远不执行。
    • 每次调用函数时,都会为此次调用开辟一块内存,内存可以保存自己以后想要用的值。
    • 函数是作用域,如果自己作用域中没有,则往上级作用域找。

    5.3 函数高阶

    5.3.1 函数中高阶(重点)

    1. 函数的变换

      def func():
          print('小米手机真的好')  #  这里func--------->指向函数的内存地址
      print(id(func))   #  33627808
      a = '小米手机真的好'
      print(id(a))     #  35196048
      #  函数的名字和变量类似,有类似的指向关系.变量指向一块内存地址放置数据,函数也指向一块内存地址放置数据
      
      
    2. 函数名当做变量使用

      def func():
          print('小米手机真的好')  
      print(id(func))   #  33627808
      a = '小米手机真的好'
      print(id(a))     #  35196048
      
      fuck_world = func
      print(id(fuck_world))    #33627808 ,2者内存地址一致.
      fuck_world()  # 调用函数,打印'小米手机真的好'
      
      
      
    3. 函数名作为列表/元组/字典元素(是不可变类似,可以做字典的键<-------->str)

      def func1():
          print('快活啊')
          
      func_list = [func1, func1, func1]
      func_list[0]()
      func_list[1]()
      func_list[2]()   # 类似的用法,调用函数运行,注意: 加上括号就可以运行该函数了
      for item in func_list:
          v = item()    #  函数语句没有retun,返回值默认为None
          print(v)   
      
    4. 函数可以当作参数进行传递 --->构造字典和函数的对应关系,避免重复if else

      def func3(arg):
          v = arg()
          print(arg())
          print(arg)
      
      
      def show():
          return 999
      
      func3(show)    # 调用函数,把show函数当做参数使用.
      
      
      • 面试题相关

        def func3():
            print('话费查询')
        def func4():
            print('流量办理')
        def func5():
            print('充值')
        def func6():
            print('人工服务')
        
        info = {
            'k1':func3,
            'k2':func4,
            'k3':func5,
            'k4':func6
        }
        
        content = input('请输入你要办理的业务:')
        function_name = info.get(content)
        function_name()          # 运用字典调用函数
        
    5. 函数可以做返回值

      def func():
      	print('name')
          
      def show()
      	return func
      # ******************  
      v = show()
      
      v()   # 执行打印name     
      #********************
      show()()  # 相当于show()()
      
    6. 函数的闭包--->封装了值,内层函数调用才是闭包,缺一不可 .

      • 闭包概念:为函数创建一块区域并为其维护自己数据,以后执行时方便调用。【应用场景:装饰器 / SQLAlchemy源码】

        name = 'oldboy'
        def bar(name):
            def inner():
                print(name)
            return inner
        v1 = bar('alex') # { name=alex, inner }  # 闭包,为函数创建一块区域(内部变量供自己使用),为他以后执行提供数据。
        v2 = bar('eric') # { name=eric, inner }  ,2者不干扰运行.
        v1()
        v2()
        
        # 不是闭包
        def func1(name):
            def inner():
                return 123
            return inner 
        
        # 是闭包:封装值 + 内层函数需要使用。
        def func2(name):
            def inner():
                print(name)
                return 123
            return inner 
        
    7. 数据类型中那些有返回值

      # 无返回值
        v = [11,22,33]
        v.append(99) # 无返回值
        
      # 仅有返回值:
        v = "alex"
        result = v.split('l')
        
        v = {'k1':'v2'}
        result1 = v.get('k1')
        result2 = v.keys()
      # 有返回+修改数据 (少)
        v = [11,22,33]
        result = v.pop()
      
    8. 常用数据类型方法返回值(重点)

      - str
        - strip,返回字符串
        - split,返回列表
        - replace,返回字符串
        - join,返回字符串。
      - list
        - append,无
        - insert,无
        - pop,返回要删除的数据
        - remove,无
        - find/index,返回索引的位置。
      - dict
        - get
        - keys
        - values
        - items
      

    5.3. 2 lambda函数(匿名函数)

    用于表示非常简单的函数,就如三元运算和if 语句一样.

    • lambad函数只能用一行代码

      # lambda表达式,为了解决简单函数的情况,如:
      
      def func(a1,a2):
          return a1 + 100 
      
      func = lambda a1,a2: a1+100       #   2者等价,注意冒号后接代码,自动return 
      
      
    • 应用

      func = lambda a,b:a if a > b else b
      t =  func(1,5)
      print(t)   #  求2个数里面较大的数
      
      # 练习题1
      USER_LIST = []
      def func0(x):
          v = USER_LIST.append(x)
          return v 
      
      result = func0('alex')
      print(result)
      
      
      # 练习题2
      
      def func0(x):
          v = x.strip()
          return v 
      
      result = func0(' alex ')
      print(result)
      
      ############## 总结:列表所有方法基本上都是返回None;字符串的所有方法基本上都是返回新值 
      
      

    5.4 python内置函数简介

    5.4.1自定义函数

    5.4.2内置函数

    • 输入输出print input

    • 强制转换类型

      • dict()
      • list()
      • tuple()
      • int()
      • str()
      • bool()
      • set()
    • 其他

      • len
      • open
      • range
      • id
      • type
    • 数学相关

      • abs 求绝对值

      • float ,转换为浮点型(小数)

      • max /min

      • sum 求和

      • divmod ,获取2数字相除的商和余数

      • pow ,指数函数,获取指数

        v = pow(2,5)
        print(v)  # 2^5 = 32
        
        
      • round函数,四舍五入函数

        v= round(1.24879,2) #小数点后取2位
        print(v)  #  1.25
        ##############################################
        # 注意:由于计算机精度问题,round函数可能会出错
        round(2.355,2)   # 算得的是 2.35  ,py版本3.6.8
        
    • 编码相关

      • chr() ,将十进制转化unicode编码中对应的字符串

        v =chr(152)
        print(v)
        
        i = 1
        while i < 1000:
            print(chr(i))
            i += 1
        
      • ord(), 根据字符在unicode编码的对应关系,找到对应的十进制.

        v= ord("字")   #  一次只能索引一个字符
        print(v)
        
        content = """一天,我正在路上走着,突然一声
        雄浑有力的声音传进我的耳朵里。"""
        for i in content:
            print(ord(i))
        
      • 应用: 随机验证码(重点)

        import random     # 调用随机数函数
        
        def get_random_code(length=6):
            data = []
            for i in range(length):
                v = random.randint(65,90)  # 65-90对应的是ABC-----Z
                data.append(chr(v)
            return  ''.join(data)
        
        code = get_random_code()
        print(code)
        
    • 进制转换

      • bin() 10进制转为2进制 ,''0b"

      • oct() 10进制转为8进制 ." 0o"

      • hex() 10进制转为16进制 ."0x"

      • int() 把````数转为10进制数 ,base默认为10 ,转二进制数base = 2,base = 8, base = 16

        num= 192
        n1 = bin(num)
        n2 = oct(num)
        n3 - hex(num)
        
        print(n1,n2,n3)
        
        # 二进制转化成十进制
        v1 = '0b1101'
        result = int(v1,base=2)
        print(result)
        
        # 八进制转化成十进制
        v1 = '0o1101'
        result = int(v1,base=8)
        print(result)
        
        # 十六进制转化成十进制
        v1 = '0x1101'
        result = int(v1,base=16)
        print(result)                #  注意,转换时0b   0o   0x可以不用加
        

    5.4.3 高级函数(必考)

    • map() 循环每个元素(第二个参数),然后让每个元素执行函数(第一个参数),将每个函数执行的结果保存到新的列表中,并返回。

      第一个参数 function 以参数序列中的每一个元素调用 function 函数,返回包含每次 function 函数返回值的新列表。

      content = [11,22,33,44,55,66,77,88,99]
      t = map(lambda x: x*x,content)
      print(list(t))  #列表元素的个数是相同的
      
    • filter(筛选/过滤)filter() 函数用于过滤序列,过滤掉不符合条件的元素,返回由符合条件元素组成的新列表。

      该接收两个参数,第一个为函数,第二个为序列,序列的每个元素作为参数传递给函数进行判,然后返回 True 或 False,最后将返回 True 的元素放到新列表中。

      content = [11,0,33,55,66,77,88,99]
      t = filter(lambda x: x < 50,content)
      print(list(t))  #列表元素的个数是相同的
      
    • reduce()reduce() 函数会对参数序列中元素进行累积。

      函数将一个数据集合(链表,元组等)中的所有数据进行下列操作:用传给 reduce 中的函数 function(有两个参数)先对集合中的第 1、2 个元素进行操作,得到的结果再与第三个数据用 function 函数运算,最后得到一个结果。

      import functools
      
      t = [3,2,3,4,5,6,8,9]
      v = functools.reduce(lambda x,y: x ** y,t)
      print(v)
      

      注意: 在py3中,reduce的函数移到了functools模组,要用这个功能,必须 import functools

    5.5 装饰器(重点)

    装饰器:在不改变原函数内部代码的基础上,在函数执行之前和之后自动执行某个功能。

    5.5.1装饰器

    示例:
    # #########################################
    def func(arg):
        def inner():
            arg()
        return inner
    
    def f1():
        print(123)
    
    v1 = func(f1)
    v1()
    # ###########################################
    def func(arg):
        def inner():
            arg()
        return inner
    
    def f1():
        print(123)
        return 666
    
    v1 = func(f1)   # 运行func(),创建一块空间,定义 inner函数.返回值 inner
    result = v1() # 执行inner函数 / f1含函数 -> 123 
    print(result) # None
    # ###########################################
    def func(arg):
        def inner():
            return arg()
        return inner
    
    def f1():
        print(123)
        return 666
    
    v1 = func(f1)
    result = v1() # 执行inner函数 / f1含函数 -> 123
    print(result) # 666
    
    示例:
    # #########################################
    def func(arg):
        def inner():
            arg()
        return inner
    
    def f1():
        print(123)
    
    v1 = func(f1)
    v1()
    # ###########################################
    def func(arg):
        def inner():
            arg()
        return inner
    
    def f1():
        print(123)
        return 666
    
    v1 = func(f1)   # 运行func(),创建一块空间,定义 inner函数.返回值 inner
    result = v1() # 执行inner函数 / f1含函数 -> 123 
    print(result) # None
    # ###########################################
    def func(arg):
        def inner():
            return arg()
        return inner
    
    def f1():
        print(123)
        return 666
    
    v1 = func(f1)
    result = v1() # 执行inner函数 / f1含函数 -> 123
    print(result) # 666
    
    

    5.5.2装饰器的本质

    def func(arg):
        def inner():
            print('before')  
            v = arg()
            print('after')
            return v 
        return inner 
    
    def index():
        print('123')
        return '666'
    
    index = func(index)  # --->指向inner函数.
    index()    # ---> 运行inner函数-->运行打印'before'/原index函数()/运行打印'after'
    
    
    1. 装饰器的格式

      def func(arg):
          def inner():
              v = arg()
              return v 
          return inner 
      
      # 第一步:执行func函数并将下面的函数参数传递,相当于:func(index)
      # 第二步:将func的返回值重新赋值给下面的函数名。 index = func(index)
      @func    #  @func等价于上面2步
      def index():
          print(123)
          return 666
      
      print(index)
      
      
    2. 应用

      # 计算函数执行时间
      def wrapper(func):
          def inner():
              start_time = time.time()
              v = func()
              end_time = time.time()
              print(end_time-start_time)
              return v
          return inner
      
      @wrapper
      def func1():
          print(123454987+865484)
          
      func1()   # --->自动启动装饰器
          
      
      
    3. 总结

      • 目的:在不改变原函数的基础上,再函数执行前后自定义功能。

      • 编写装饰器 和应用

        # 装饰器的编写
        def x(func):
            def y():
                # 前
                ret = func()
                # 后
                return ret 
           	return y 
        
        # 装饰器的应用
        @x
        def index():
            return 10
        
        @x
        def manage():
            pass
        
        # 执行函数,自动触发装饰器了
        v = index()
        print(v)
        
        
        @xx  # index = xx(index)
        def index():
            pass
        index()
        
      • 应用场景:想要为函数扩展功能时,可以选择用装饰器。

    4. 重点内容装饰器(重点)

      def 外层函数(参数): 
          def 内层函数(*args,**kwargs):   # -->无论被装饰函数有多少个参数,都能用万能参数传入.
              return 参数(*args,**kwargs)
          return 内层函数
      
      @外层函数
      def index():
          pass
      
      index()    # --->自动调用装饰器
      
    5. 装饰器建议写法

      def x1(func):
          def inner(*args,**kwargs):
              data = func(*args,**kwargs)
              return data
          return inner 
      
      def x1(func):
          def inner(*args,**kwargs):
              print('调用原函数之前')
              data = func(*args,**kwargs) # 执行原函数并获取返回值
              print('调用员函数之后')
              return data
          return inner 
      
      @x1
      def index():
          print(123)
          
      index()  
      

    5.5.3带参数的装饰器

    1. 基本格式

      def wrapper(func):
          def inner(*args,**kwargs):
              
              v = func()
              
              return v
          return i
      
    2. 装饰器加上参数(外层函数必须以函数名作为参数,要给装饰器加上参数,在外层再套一层函数)

      def super_wrapper(counter):  # counter 装饰器参数
          print(123)
          def wrapper(func):
              print(456)
              def inner(*args, **kwargs):  # 参数统一的目的是为了给原来的index函数传参
                  data = []
                  for i in range(counter):
                      v = func(*args, **kwargs)  # # 参数统一的目的是为了给原来的index函数传参
                      data.append(v)
                  return data
              return inner
          return wrapper
      
      @super_wrapper(9):    # 这时已经打印 123   456   # # func = 原来的index函数u
      											# index = inner
                                        # 已经运行super_wrapper函数和wrapper函数
              
      def index(i):
          print(i)
          return i+1000
      
      print(index(456))          # 调用index函数(带装饰器)
      
      # ################## 普通装饰器 #####################
      def wrapper(func):
          def inner(*args,**kwargs):
              print('调用原函数之前')
              data = func(*args,**kwargs) # 执行原函数并获取返回值
              print('调用员函数之后')
              return data
          return inner 
      
      @wrapper
      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)
      def index():
          pass
      
      
      • 基本装饰器更重要8成
      • 带参数的装饰器2成
      • 装饰器本质上就是一个python函数,它可以让其他函数在不需要任何代码变动的前提下增加额外的功能 ,装饰器的返回值也是一个函数对象,她有很多的应用场景,比如:插入日志,事物处理,缓存,权限装饰器就是为已经存在的对象 添加额外功能

    5.6 推导式

    5.6.1列表推导式

    • 目的: 为了方便生成一个列表

      #####基本格式#####
      v1 = [i for i in range(9)]    # 创建列表10个元素
      v2 = [i for i in range(9) if i > 5]   #对每个i,判断if i > 5,为真则添加到列表中
      v3 = [99 if i > 55 else 66 for i in range(9)]   # 三木运算
      """
      v1 = [i for i in 可迭代对象 ]
      v2 = [i for i in 可迭代对象 if 条件 ] # 条件为true才进行append
      """
      ######函数######
      
      def func():
          return i
      v6 = [func for i in range(10)]  # 10个func组成的列表,内存地址一致.
      result = v6[5]()     # 运行报错,提示 i 没有被定义,
      
      v7 = [lambda :i for i in range(10)]  # 10个lambda函数组成的列表,内存地址不一致,有10个
      result = v7[5]()   # 运行不报错,输出result 为 9
      
      ## 第一个func和列表生成器函数作用域都在第一级,找不到 i 
      ## 第二个lambda上级是列表生成器函数作用域
      
      
      ###面试题
      v8 = [lambda x:x*i for i in range(10)] # 新浪微博面试题
      # 1.请问 v8 是什么?    10个lambda函数,内存地址不一样,构建的列表
      # 2.请问 v8[0](2) 的结果是什么?    i 在列表生成式函数作用域里面,lambda是奇子集,i = 9,输出18
      
      ### 面试题
      def num():
          return [lambda x:i*x for i in range(4)]
      # num() -> [函数,函数,函数,函数]
      print([ m(2) for m in num() ]) # [6,6,6,6]
      
      

    5.6.2集合推导式

    • 和列表推导式类似,这不再赘述.

    5.6.3字典推导式

    v1 = { 'k'+str(i):i for i in range(10) }  # 和列表类似,中间有:区分键和值.
    

    5.7 迭代器

    5.7.1自己不用写迭代器,只.

    # 一一展示列表中的元素
    # 1.for 循环    2. while + 索引 + 计数器
    # 使用迭代器--->对 某种对象(str/list/tuple/dict/set类创建的对象)-可迭代对象中的元素进行逐一获取,表象:具有`__next__`方法且每次调用都获取可迭代对象中的元素(从前到后一个一个获取)。
    # 可被for 循环的---> 可迭代对象
    
    
    #***************************************************************#
    v1 = [1,2,3,4]
    v2 = iter(v1)    # --->v2是一个迭代器
    #或者  v2 = v1.__iter__()
    
    # 迭代器想要获取每个值:-->反复调用
    while 1 :
    	val = v1.__next__() 
        print(val)
     
    ##### *********   ######
    v3 = "alex"
    v4 = iter(v1)
    while True:
        try:
            val = v2.__next__()
            print(val)
        except Exception as e:
            break
    
            
            
    # 直到报错:StopIteration错误,表示已经迭代完毕。
    
    
    1. 判定是否是迭代器 --> 内部是否有__next__方法

    2. for 循环---->为这简便有了for 循环

      v1 = [11,22,33,44]
      
      # 1.内部会将v1转换成迭代器
      # 2.内部反复执行 迭代器.__next__()
      # 3.取完不报错
      
      for item in v1:
          print(item)
      

    5.7.2可迭代对象

    • 内部具有 __iter__() 方法且返回一个迭代器。(*)

      v1 = [11,22,33,44]
      result = v1.__iter__()
      
    • 可以被for循环

    5.7.3 小结

    • 迭代器,对可迭代对象中的元素进行逐一获取,迭代器对象的内部都有一个 __next__方法,用于以一个个获取数据。
    • 可迭代对象,可以被for循环且此类对象中都有 __iter__方法且要返回一个迭代器(生成器)。

    5.8 生成器

    生成器(变异函数---->特殊的迭代器)

    生成器,函数内部有yield则就是生成器函数,调用函数则返回一个生成器,循环生成器时,则函数内部代码才会执行。

    1. 函数样式

      # 函数
      def func():
          return 123
      func()
      
      
    2. 生成器

      # 生成器函数(内部是否包含yield)---->只要有yeild就是生成器,不论是否有return
      def func():
          print('F1')
          yield 1
          print('F2')
          yield 2
          print('F3')
          yield 100
          print('F4')
      # 函数内部代码不会执行,返回一个 生成器对象 。
      v1 = func()
      # 生成器是可以被for循环,一旦开始循环那么函数内部代码就会开始执行。
      for item in v1:
          print(item)
      
    • 总结:函数中如果存在yield,那么该函数就是一个生成器函数,调用生成器函数会返回一个生成器,生成器只有被for循环时,生成器函数内部的代码才会执行,每次循环都会获取yield返回的值

      def func():
          count = 1
          while 1 :
              yield count
              count += 1
              if count == 100 :
                  return
      val = func()     # --->调用生成器函数 ---->返回值时一个生成器 --->内部代码没有执行
      for item in val :
          print(item)  # 此时才执行生成器内部代码,并yield.就冻结,直到下次再继续运行.
      
      • 示例 读文件

        def func():
            """
                分批去读取文件中的内容,将文件的内容返回给调用者。
            """
            cursor = 0
            while 1 :
                f =  open(r'D:Python学习pythons21day16goods.txt','r',encoding='utf-8-sig')
                f.seek(cursor)
                data_list = []                       # 光标移到最前
                for i in range(10):
                    line = f.readline()             # 一次读一行
                    if not line:
                        return
                    data_list.append(line)
                cursor = f.tell()             #获取光标
                f.close()                             # 关闭与redis的连接
                for row in data_list:
                    yield  row
        
        
        for itemm in func():
            p = input('qingsr123456498')
            print(itemm)
        

    5.8.1 range和 xrange区别

    • range 函数说明:range([start,] stop[, step]),根据start与stop指定的范围以及step设定的步长,生成一个序列。
    • xrange 函数说明:用法与range完全相同,所不同的是生成的不是一个数组,而是一个生成器。
    • py3中只有range,是生成器,

    5.8.2 生成器推导式

    # def func():
    #     for i in range(10):
    #         yield i
    # v2 = func()
    v2 = (i for i in range(10)) # 生成器推导式,创建了一个生成器,内部循环为执行。
    
    
    # 没有元组推导式,加括号是生成器推导式
    
    def my_range(counter):
        for i in range(counter):
            yield i
    # 生成器函数
    
    # # 面试题:请比较 [i for i in range(10)] 和 (i for i in range(10)) 的区别?
    # 前者是列表推导式,直接在内存中生成列表[1-10],后者是生成器推导式,内部循环不执行,只有for 循环才执行.
    
    # 示例一
    # def func():
    #     result = []
    #     for i in range(10):
    #         result.append(i)
    #     return result
    # v1 = func()
    # for item in v1:
    #    print(item)              # 列表推导式
    
    # 示例二
    # def func():
    #     for i in range(10):
    #         def f():
    #             return i
    #         yield f              # 生成器函数
    #
    # v1 = func()                  # 生成器,内部代码不执行
    # for item in v1:
    #     print(item())             #for 循环才执行
    

    img新人上路,请多多批评指正img

  • 相关阅读:
    Socket网络通讯
    Redis事务/持久化/发布订阅
    Redis主从复制和哨兵机制
    java8新特性Lambda(1)
    【指标测试】影响IOPS的几个重要因素
    win7:Remote Desktop Services 启动失败
    centos 6.4 安装视频解码器
    [RVM is not a function] Interating RVM with gnome-terminal
    bzoj 2179: FFT快速傅立叶 -- FFT
    bzoj 3389: [Usaco2004 Dec]Cleaning Shifts安排值班 -- 贪心
  • 原文地址:https://www.cnblogs.com/deng1821333144/p/10836911.html
Copyright © 2020-2023  润新知