第五章 函数

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学习\python\s21day16\goods.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

posted on 2019-05-09 10:13  啊,那逝去的青春  阅读(124)  评论(0编辑  收藏  举报