Python函数进阶、生成器、推导式、内置函数、匿名函数、递归

 

  • 一、装饰器进阶

    • 1、装饰标准写法,可以应对各种情况(带参数,带返回值)

      # 普通装饰器标准写法,可以满足传参和有返回值的情况
      def wrapper(f):
          def inner(*args, **kwargs):
              print("start_wrapper")
              res = f(*args, **kwargs)
              print("end_wrapper")
              return res
          return inner
      
      @wrapper  # func_test = wrapper(func_test)
      def func_test():
          print("我是func_test")
      
      func_test() # func_test = inner
      标准装饰器示例
    • 2、装饰器带参数

      # 带参数的装饰器,假如有500个函数需要反复添加装饰器,可以通过装饰器传参来实现
      FLAG = True
      def outer(FLAG):
          def wrapper(func):
              def inner(*args, **kwargs):
                  if FLAG == True:
                      print("start_wrapper")
                      res = func(*args, **kwargs)
                      print("end_wrapper")
                      return res
                  else:
                      res = func(*args, **kwargs)
                      return res
              return inner
          return wrapper
      
      @outer(FLAG)  # @outer(FLAG)  = @wrapper
      def func1():
          print("我是funcl!!!")
      func1()
      带参数的装饰器示例
    • 3、2个装饰器装饰一个函数

      #  多个装饰器装饰一个函数
      def wrapper1(f):  # f = inner2
          def inner1():
              print("我是wrapper1")
              f()  # inner2()
              print("我是wrapper1")
          return inner1
      
      def wrapper2(f): # f = func
          def inner2():
              print("我是wrapper2")
              f()  # func()
              print("我是wrapper2")
          return inner2
      
      @wrapper1  # func = wrapper1(func)= wrapper1(inner2) = inner1
      @wrapper2  # func = wrapper2(func) = inner2
      def func():
          print("我是func")
      func()  #  func = inner1 = inner1()
      多个装饰器装饰一个函数-示例1 

      #  多个装饰器装饰一个函数,实现用户登录和性能测试
      import time
      user_status = {"alex": False}
      
      # 登录装饰器
      def login(f):  # f = inner2
          def inner1(name):
              if user_status[name] == False:
                  user = input("请输入用户名:")
                  pwd = input("请输入密码:")
                  if user == "alex" and pwd == "123":
                      print("登录成功")
                      user_status[name] = True
                      f(name)  # inner2(name)
              else:
                  print("登录成功")
                  f(name)   # inner2(name)
          return inner1
      
      # 性能测试装饰器
      def timmer(f): # f = func
          def inner2(*args, **kwargs):
              start_time = time.time()
              res = f(*args, **kwargs)  # f = func
              end_time = time.time()
              print(end_time - start_time)
              return res
          return inner2
      
      @login  #  func = login(func) = login(inner2) = inner1
      @timmer  # func = timer(func) = inner2  # 向上传完值以后销毁
      def func(name):
          print("start_func")
          print("我是函数func")
          time.sleep(0.1)
          print("end_func")
      
      func("alex")  # func = inner1
      多个装饰器装饰一个函数-示例2
  • 二、迭代器和生成器

    • 1、迭代器

      # 迭代器 iterator
      # 凡是可以使用for循环取值的都是可迭代的
      # 列表,字典,元组,字符串,集合,range,文件句柄,enumerate等都是可迭代对象
      # 如何查看对象是否可迭代 dir
      lst = [1, 2, 3]
      print(dir(lst))  # 含有'__iter__'方法就是可迭代的
      
      # 怎么把可迭代对象变成迭代器
      lst_iter = iter(lst)
      lst_iter1 = lst.__iter__()
      # 备注:上面lst_iter 和 lst_iter1是两个生成器
      
      # 如何查看lst_iter是不是迭代器
      print(dir(lst_iter))  # 含有__iter__方法和__next__方法的就是迭代器
      
      # 如何迭代器中取值?
      # 第一种 :next  随时都可以停止 最后一次会报错
      print(next(lst_iter))  # 结果 1
      print(lst_iter.__next__())  # 结果 2
      print(next(lst_iter))  # 结果 3
      
      # 解决取不到值会报错StopIteration, try except异常捕捉
      while True:
          try:
              print(next(lst_iter))  # lst_iter.__next__()
          except StopIteration:
              break
      
      # 第二种 :for循环 从头到尾遍历一次 不遇到break、return不会停止
      for i in lst_iter:
          print(i)
      
      # 第三种 :list tuple 数据类型的强转  会把所有的数据都加载到内存里 非常的浪费内存
      print(lst_iter)
      print(list(lst_iter))
      
      # 问题 : ranger(100)是迭代器吗?
      # range(100) 不是迭代器,但是一个可迭代对象。使用iter可以变成迭代器
      
      # py2 range 不管range多少 会生成一个列表 这个列表将用来存储所有的值
      # py3 range 不管range多少 都不会实际的生成任何一个值
      
      # 可迭代协议 :内部含有__iter__方法的都是可迭代的
      # 迭代器协议 :内部含有__iter__方法和__next__方法的都是迭代器
      
      # 迭代器的优势:
      #     节省内存
      #     取一个值就能进行接下来的计算 ,而不需要等到所有的值都计算出来才开始接下来的运算 —— 快
      
      # 迭代器的特性:惰性运算
    • 2、生成器

      # 生成器 Generator
      # 自己写的迭代器 就是一个生成器
      # 两种自己写生成器(迭代器)的机制:生成器函数 生成器表达式
      # 生成器函数
      def generator():
          for i in range(10):
              yield i
      g = generator()
      
      while True:  # 通过循环取生成器里面的所有值
          try:
              print(next(g))
          except StopIteration:
              break
              
      # 示例,生产20000件衣服。
      def generator():
          for i in range(1, 20001):
              yield "制作第%s件衣服" % (i,)
      g = generator()
      
      # 取10件衣服
      for i in range(1, 11):
          print(next(g))
      
      
      # 凡是带有yield的函数就是一个生成器函数
      def func():
          print('****')
          yield 1
          print('^^^^')
          yield 2   # 记录当前所在的位置,等待下一次next来触发函数的状态
      
      g = func()
      print('--',next(g))
      print('--',next(g))
      # 生成器函数的调用不会触发代码的执行,而是会返回一个生成器(迭代器)
      # 想要生成器函数执行,需要用next
      
      def cloth_g(num):
          for i in range(num):
              yield 'cloth%s'%i
      
      g = cloth_g(1000)
      print(next(g))
      print(next(g))
      print(next(g))
      # 生成器示例 文件监听
      # 监听函数
      import time
      def listen_file(filename):
          with open(filename) as f1:
              while True:
                  # f1.seek(0, 2)  # 光标移到文件尾部
                  res = f1.readline()  # 每次只读一行,readline 会一直读如果已经到最后一行则返回空。readline不会停止所以用readline
                  if res.strip():
                      f1.seek(0, 2)
                      yield res.strip()
                  time.sleep(0.1)  # 0.5秒获取一次监听
      g = listen_file("tmp")
      for i in g:
          print(i)
      
      # 循环写文件
      import time
      count = 1
      while True:
          with open("tmp", mode="a") as f1:
              f1.write("我是第%s行\n" % (count,))
          count += 1
          time.sleep(1)
      生成器示例:文件监听
      # send关键字
      def func():
          print(11111)
          ret1 = yield 1
          print(22222, 'ret1 :', ret1)
          ret2 = yield 2
          print(33333, 'ret2 :', ret2)
          yield 3
      
      g = func()
      print(next(g))  # 结果是 11111
      print(g.send('alex'))  # 在执行next的过程中 传递一个参数给yield1
      print(g.send('金老板'))  # 在执行next的过程中 传递一个参数给yield2
      #send 获取下一个值的效果和next基本一致
      #只是在获取下一个值的时候,给上一yield的位置传递一个数据
      #使用send的注意事项
          # 第一次使用生成器的时候 是用next获取下一个值
          # 最后一个yield不能接受外部的值
      # 想生成器中传递值 有一个激活的过程 第一次必须要用next触发这个生成器
      生成器-send
      def func_g(num = 0):
          sums = 0
          day = 0
          avg = 0
          while True:
              money = yield avg  # 返回avg,并接受seed传进来的money
              sums += money  # sums = sums + money
              day += 1
              avg = sums/day
      
      g = func_g()
      print(next(g))
      print(g.send(50))
      print(g.send(100))
      print(g.send(300))
      send示例:移动平均值
      # 示例:生成器预激活,使用send必须next预激活一下,可以用装饰器来操作预激活
      def wrapper(f): # f = func_g
          def inner(*args, **kwargs):
              g = f(*args, **kwargs) # f = func_g
              next(g)
              return g  # 必须返回生成器
          return inner
      
      @wrapper  # func_g = wrapper(func_g)
      def func_g(num = 0):
          sums = 0
          day = 0
          avg = 0
          while True:
              money = yield avg  # 返回avg,并接受seed传进来的money
              sums += money  # sums = sums + money
              day += 1
              avg = sums/day
      
      g = func_g()  # func_g  = inner ()
      print(g.send(50))
      print(g.send(100))
      print(g.send(300))
      预激活
      # yield from
      # 普通生成器函数
      def func_g():
          for i in range(5):
              yield i
          print("----------")
          for i in range(10):
              yield i
      g = func_g()
      
      # 装逼版生成器函数
      def func_g():
          yield from range(5)
          print("----------")
          yield from range(10)
      g = func_g()
      
      while True:
          try:
              print(g.__next__())
          except StopIteration:
              break
      yield from
    • 3、列表推导式生成器表达式

      # 开篇
      #老男孩由于峰哥的强势加盟很快走上了上市之路,alex思来想去决定下几个鸡蛋来报答峰哥
      agg_list = ["鸡蛋%s" % i for i in range(1, 10)]  # 列表推导式
      print(agg_list)
      #峰哥瞅着alex下的一筐鸡蛋,捂住了鼻子,说了句:哥,你还是给我只母鸡吧,我自己回家下
      laomuji = ("鸡蛋%s" % i for i in range(1, 10))   # 生成器表达式
      print(laomuji)
      print(laomuji.__next__())  # 下一个鸡蛋
      print(laomuji.__next__())  # 下二个鸡蛋
      print(laomuji.__next__())  # 下三个鸡蛋
      ...
      
      
      # 总结:
      # 1.把列表解析的[]换成()得到的就是生成器表达式
      # 2.列表解析与生成器表达式都是一种便利的编程方式,只不过生成器表达式更节省内存
      # 3.Python不但使用迭代器协议,让for循环变得更加通用。大部分内置函数,也是使用迭代器协议访问对象的。
      # 例如, sum函数是Python的内置函数,该函数使用迭代器协议访问对象,而生成器实现了迭代器协议,所以,我们可以直接这样计算一系列值的和:
      res = sum(i for i in range(1, 101))
      print(res)
      res1 = sum([i for i in range(1, 101)])
      print(res1)
      #
      # 列表解析
      sum([i for i in range(100000000)])  # 内存占用大,机器容易卡死
      # 生成器表达式
      sum(i for i in range(100000000))  # 几乎不占内存
      # 面试题1
      def demo():
          for i in range(4):
              yield i
      
      g=demo() # g 是生成器
      
      g1 = (i for i in g)  # g1 是生成器
      g2 = (i for i in g1)  # g2 也是生成器
      
      print(list(g1))  # 从g1生成器取值,g1又从g生成器中取值,用list会取出生成器内的所有值
      print(list(g2))  # 从g2生成器取值,g2又从g1生成器中取值,g1又从g中取值。g生成器已经被取完,所以取不到值
      生成器-面试题1
      # 面试题2
      def add(n,i): # 定义一个求和函数
          return n+i # 返回和
      
      def test(): # 生成器函数,里面有4个值0,1,2,3
          for i in range(4):
              yield i
      
      g=test() # g = 生成器
      for n in [1,10]: # 列表里面有2个数字 1 和 10
          g = (add(n, i) for i in g)
          # n = 1
          # g=(add(n,i) for i in g)
          # n = 10
          # g=(add(n,i) for i in g)
      
      
      print(list(g)) # g = (add(n,i) for i in (add(10,i) for i in g)) --> (add(n,i) for i in (add(10,i) for i in (0,1,2,3,4))) -->
                     #  (add(10,i) for i in (10,11,12,13) --->(20,21,22,23) --->[20,21,22,23]
      生成器-面试题2
  • 三、内置函数

    • 1、基础数据类型相关

      • 1)和数字相关
        # bool
        print(bool(1)) # True
        print(bool(0)) # False
        print(bool("")) # False
        print(bool(" ")) # True
        print(bool([])) # False
        
        # int
        a = "123"
        print(type(int(a)))  # <class 'int'>
        
        # float
        a = 100
        print(float(a)) # 100.0 转换成浮点类型
        数据类型
        # 进制转换
        
        # bin 二进制
        a = 100
        print(bin(a))   # 0b1100100
        
        # oct 八进制
        print(oct(a))   # 0o144
        
        # hex 十进制
        print(hex(a))   # 0x64
        进制转换
        # abs 绝对值
        a = -100
        print(abs(a)) # 100
        
        # divmod 返回(除,余)
        print(divmod(100, 3))  # (33, 1)
        
        # round 小数精确
        a = 3.145236
        print(round(a)) # 3
        print(round(a, 2)) # 3.15 可以指定精确位数,四舍五入
        
        # pow  幂运算(x,y,z)
        # print(pow(2,3,5))  # (2**3)%5
        # print(pow(3,2,2))
        
        # sum 求和
        res = sum(i for i in range(10))  # 生成器表达式可以用在sum求值
        print(res)
        lst = [1,2,3,4,5]
        print(sum(lst)) # 所有可迭代int类型对象都可以求和
        print(sum([1,2,3,4,5],10))
        
        
        # min 最小值
        print(min(lst))
        print(min(lst, key=lambda x: abs(x - 5)))
        print(min(1,-2,3,-4,key=abs))
        def func(num):
            return num%2
        print(min(-2,3,-4,key=func))
        
        # max 最大值
        print(max(lst))
        数学运算
      • 2)和数据结构相关
        • 序列
          # 元组和列表不做详细说明
          list()
          tuple()
          列表元组
          # reversed  反转可迭代对象,返回一个迭代器
          lst = [1, 2, 3, 4, 5]
          res = reversed(lst)
          print(dir(reversed(lst)))
          print(res.__next__())
          print(res.__next__())
          print(res.__next__())
          print(res.__next__())
          print(res.__next__())
          相关内置函数
          # str 字符串
          
          # bytes
          s = "abcd"
          s1 = s.encode(encoding="utf-8") # unicode转换成bytes(utf-8)的类型
          print(s1)  # b'abcd'
          s2 = s1.decode(encoding="utf-8") # 把 bytes(以utf-8存储)转换成unicode类型
          print(s2)  # abcd
          
          # repr
          print(1)
          print('1')
          print(repr(1))
          print(repr('1'))
          
          # ord 和  chr 对应ascii码表
          # print(ord('a'))    # 小写的a-z 97+26  A-Z 65+26
          # print(chr(97))
          
          # format
          print(format('test', '<20'))
          print(format('test', '>20'))
          print(format('test', '^20'))
          字符串
        • 数据集合
          dict() # 字典
          
          set() # 集合
          
          frozenset()  # 不可变集合
        • 相关内置函数 
          # numerate
          l = ['苹果', '香蕉']
          ret = enumerate(l, 1)   # 枚举  接收两个参数:一个容器类型,一个序号起始值   返回值:可迭代的
          print(ret)
          for num, item in enumerate(l, 1):
              print(num, item)
          
          # all 和 any
          print(all([1,2,3,4,5]))
          print(all([0,1,2,3,4,5]))
          print(all(['a',1,2,3,4,5]))
          print(all(['',1,2,3,4,5]))
          print(any([0,None,False]))
          
          # zip
          ret = zip([1,2,3,4,5],('a','b','c','d'),(4,5))   #拉链方法
          print(ret)
          for i in ret:
              print(i)
          
          
          # filter  对元素进行处理过滤,返回处理前的元素
          # 过滤所有偶数
          lst = [1, 4, 6, 7, 9, 12, 17]
          def func(num):
              if num % 2 == 0:return True
          filter(func,lst)
          for i in filter(func, lst):
              print(i)
          
          # 过滤所有None或者空元素
          l = ['test', None, '', 'str', '  ', 'END']
          def func(item):
              if item and item.strip():return True
          for i in filter(func,l):
              print(i)
          
          # map  把元素进行处理,并返回处理过的元素
          def func(num):
              return num ** 2
          for i in map(func,range(10)):print(i)
          
          
          # sorted 和 sort一样 排序功能
          l = [1,-4,-2,3,-5,6,5]
          l.sort(key = abs)
          print(l)
          l = [1,-4,-2,3,-5,6,5]
          new_l = sorted(l,key=abs,reverse=True)
          print(new_l)
          
          l = [[1,2],[3,4,5,6],(7,),'123']
          print(sorted(l,key=len))
          相关内置函数
    • 2、作用域相关

      def func():
          a = 1
          b = 2
          print(locals())
          print(globals())
      # 全局命名空间中的名字
      print(locals())   # 本地的命名空间
      print(globals())  # 全局的命名空间
      func()
      locals()和globals()
    • 3、迭代器生成器相关

      range()
      
      next()
      
      iter()
      迭代器生成器相关
    • 4、其他:

      # eval 和 exec  区别是前者可以执行运算,其他均一样
      eval()
      eval('print(123)')
      exec('print(123)')
      print(eval('1+2-3*20/(2+3)'))
      print(exec('1+2-3*20/(2+3)'))
      字符串类型代码执行
      # input()
      
      # print()
      print(123, end="") # 不换行
      print(123, end="")
      
      # 进度条
      import time
      for i in range(1,101):
          print("\r%s %%%s" % (i, "#"*i), end="")
          time.sleep(0.3)
      输入输出相关
      #  hash()
      print(hash("1231231")) #1231231236604643238473253898
      
      # 对可hash的数据类型进行hash之后会得到一个数字
      # 在一次程序的执行过程中 对相同的可哈希变量 哈希之后的结果永远相同的
      # 在一次程序的执行过程中 对不相同的可哈希变量 哈希之后的结果几乎总是不相同的
      
      # id () 查看对象的内存地址
      内存相关
      dir()
      查看内置属性
  • 四、匿名函数

    # lambda 表达式
    # 普通函数
    def func(a, b):
        return a + b
    
    #lambda 表达式
    func1 = lambda a,b: a + b
    
    print(func(1, 2))
    print(func1(1, 2))
    
    # 示例1
    # 普通写法
    def func(num):
        return num ** 2
    for i in map(func,range(10)):print(i)
    
    # lambda写法
    for i in map(lambda num: num ** 2, range(10)): print(i)
    
    # 示例2
    # 普通写法
    def func(num):
        return num % 2
    print(min(-2,3,-4,key=func))
    
    # lambda写法
    print(min(-2, 3, -4, key=lambda num: num % 2))
    
    # 示例3
    d = lambda p: p*2
    t = lambda p: p*3
    x = 2
    x = d(x)   # x = 4
    x = t(x)   # x = 12
    x = d(x)   # x = 24
    print(x)   # x = 24
    
    # 练习1
    # 现有两元组(('a'), ('b')), (('c'), ('d')), 请使用python中匿名函数生成列表[{'a': 'c'}, {'b': 'd'}]
    def func1(t):
        return {t[0]:t[1]}
    res = map(func1,zip((('a'), ('b')), (('c'), ('d'))))
    print(list(res))
    
    res = map(lambda t: {t[0]: t[1]}, zip((('a'), ('b')), (('c'), ('d'))))
    print(list(res))
    
    # 练习2
    # 以下代码的输出是什么?请给出答案并解释。
    def multipliers():
        return [lambda x:i*x for i in range(4)] #
    
    print([m(2) for m in multipliers()])
    
    
    # 解析:
    # 第一步分解 def multipliers():
    def multipliers():
        lst = []
        for i in range(4):
            lst.append(lambda x:i*x)
        return lst
    # 第二步展开 def multipliers():
    def multipliers():
        lst = []
        i = 0
        lst.append(lambda x:i*x)
        i = 1
        lst.append(lambda x:i*x)
        i = 2
        lst.append(lambda x:i*x)
        i = 3
        lst.append(lambda x:i*x)
        return lst
    # 第三步 分解[m(2) for m in multipliers()]
    lst1 = []
    for m in multipliers(): # multipliers() = lst[lambda x:i*x,lambda x:i*x,lambda x:i*x,lambda x:i*x]
        m(2) # m = lambda x:i*x
             # m(2) 执行函数传参2   
  • 五、递归

    # 递归的定义——在一个函数里再调用这个函数本身,实际操作中递归必须要有个可停止的条件。
    # 递归解析为递推和回溯两步,先递推当满足条件以后开始回溯
    # 递归的最大深度—997
    # RecursionError: maximum recursion depth exceeded while calling a Python object
    def func():
        print(1)
        func()
    func()
    
    #  测试递归的最大深度
    def foo(n):
        print(n)
        n += 1
        foo(n)
    foo(1)
    
    import sys
    #  修改递归的最大深度,一般不修改,如果默认递归深度解决不了 说明这个问题不能用递归解决
    sys.setrecursionlimit(2000)
    
    # 用递归计算6*5*4*3*2*1的乘积
    print(6*5*4*3*2*1)
    def fn(n):
        if n == 1:return 1
        return n*fn(n-1)
    print(fn(6))
    
    # 第一次fn(6)  # 返回值 6*fn(6-1)= 720
    def fn(n): # n = 6
        if 6 == 1:return 1
        return 6*fn(6-1)
    
    # 第二次fn(6-1) # 返回值 5*fn(5-1) = 120
    def fn(n): # n = 5
        if 5 == 1:return 1
        return 5*fn(5-1)
    
    # 第三次fn(5-1)  # 返回值 4*fn(4-1) = 24
    def fn(n): # n = 4
        if 4 == 1:return 1
        return 4*fn(4-1)
    
    # 第四次fn(4-1) # 返回值 3*fn(3-1) = 6
    def fn(n): # n = 3
        if 3 == 1:return 1
        return 3*fn(3-1)
    
    # 第五次fn(3-1) # 返回值 2*fn(2-1) = 2
    def fn(n): # n = 2
        if 2 == 1:return 1
        return 2*fn(2-1)
    
    # 第六次fn(2-1)   返回值 fn(2-1)= 1
    def fn(n): # n = 2
        if 1 == 1:return 1
        return 2*fn(2-1)
    
    
    # 练习 打印列表的元素
    li = [1, [2, [3, [4, [5]]]]]
    
    def fun(li):
        for i in li:
            if type(i) == list:
                fun(i)
            else:
                print(i)
    fun(li)

     

     

     

 

posted @ 2018-04-27 21:33  S.Curry  阅读(309)  评论(0编辑  收藏  举报