zoukankan      html  css  js  c++  java
  • 生成器,迭代器,装饰器

    生成器 (generator)

    • 概念

      • 在Python中, 一边循环一边计算的机制, 称为生成器: generator 创建生成器: G = ( x*2 for x in range(5)) 可以通过 next(生成器) 函数获得生成器的下一个返回值 没有更多的元素时, 抛出 StopIteration 的异常 生成器也可以使for 循环,因为生成器也是可迭代对象
    • 生成器的生成方式1:

      list2 = [x for x in range(10)]
      print(type(list2))
      # 得到一个生成器对象
      g = (x*2 for x in range(10))
      print(type(g))
      # 打印生成器生成的第一个数字
      print(next(g))
      print(next(g))
      print(next(g))
      一共10个数字,打印超出报StopIteration异常
      
      • 应用: 求斐波那契数列的第n个数
      def fibo(n):
      a,b=1,1
      i = 3
      while i <= n:
          if i == 1 or i == 2:
              return 1
          else:
              a,b = b,a+b
              i += 1
      else:
          print(b)
    • 生成器的生成方式2(包含yield关键字的函数):

      def getNum():
           for i in range(10):
              yield i
    • 生成器中元素的访问方式:

      • 1.next()
      • 2.g.__next()
      • 3.g.send('发送的参数')
      def gen():
          print('a')
          count = yield 1
          print ('--->',count)
          print ('b')
          yield 2
      #注意打印结果
      g = gen()
      next(g)
      g.send('123')
      next(g)
    • 其他使用场景:(携程,实现两个任务的交替调用)

    def save():
        while True:
            yield
            print ('save')
    def draw():
        while True:
            yield
            print ('draw')
    
    g1 = save()
    g2 = draw()
    while True:
        next(g1)
        next(g2)

    迭代器 (Iterator)

    • 概念: 拥有__iter__方法和__next__方法的对象就是迭代器
      • 迭代
        • 迭代是访问集合元素的一种方式,可以将某个数据集内的数据“一个挨着一个的取出来”,就叫做迭代
      • 可迭代协议
        • 协议就是互相规定好的。可迭代协议的定义非常简单,就是内部实现了 __iter__方法。
      • 迭代器协议
        • 迭代器协议:必须拥有__iter__方法和__next__方法
      • 可以通过dir(对象)查看是否实现了__iter__,__next__等方法来判断对象是否为迭代器
      • 也可以使用 isinstance(Iterator)来判断
      • 练习:
        • 查看__iter__()的返回值
        • 查看__iter__()包含的方法
        • 分别查看迭代器与列表的方法
    • for循环的本质
      • 通过__iter__()获取该对象的一个迭代器对象
      • 通过__next__()函数,依次获取下一个元素

    闭包

    • 什么是闭包?
      • 在 python 中创建一个闭包一般有 3 个要求:
        • 1.闭包函数必须有内嵌函数。
        • 2.内嵌函数必须要引用外层函数的变量。
        • 3.闭包函数返回内嵌函数的地址(函数名称)
    • 创建一个闭包函数:
    def funcOut():
        name = 'Jery'
        def funcIn():
            print(name)
        return funcIn
    f = funcOut()
    f()
    • 判断是否为闭包函数
    def funcOut():
        name = 'abc'
        def funcIn():
            print(name)
            pass
        #如果打印None,则不是闭包函数
        print(funcIn.__closure__)
        return funcIn
    f=funcOut()
    f()

    装饰器

    • 装饰器的本质:(闭包函数)
    • 装饰器的作用:
      • 在不修改原函数及其调用方式的情况下对原函数功能进行扩展
    • 装饰器的使用:
      • 需求:为现有功能fun1增加日志功能
      • 传统方案解决
      • 使用闭包解决
      def outfunc(func):
          def infunc():
              writeLog()
              func()
          return infunc
      def fun1():
          print("使用功能1")
      def fun2():
          print("使用功能2")
      
      # 注意名字的问题,需要分析
      fun1 = outfunc(fun1)
      # 装饰器(闭包)
      fun1()
      使用装饰器(语法糖)解决
      def outfunc(func):
          def infunc():
              writeLog()
              func()
          return infunc
      @outfunc
      def fun1():
          print("使用功能1")
      @outfunc
      def fun2():
          print("使用功能2")
      
      fun1()
      fun2()
    • 多个装饰器的使用
    def add1(fc):
        print("add1正在装饰")
        def wrapped():
            return ""+fc()+""
        return wrapped
    def add2(fc):
        print("add2正在装饰")
        def wrapped():
            return '*'+fc()+'*'
        return wrapped
    #看到这个,开始进行装饰,而不是等到调用时
    @add1
    @add2
    def test1():
        return '金陵十三钗'
    print(test1())
    • 对有参数的函数进行装饰
    def func(fn):
        print("func")
        def func_in(aa, bb):
            print("func_in1")
            fn(aa,bb)
            print("func_in2")
        return func_in
    @func
    def test(a, b):
        print("a=%d,b=%d" % (a, b))
    # 装饰器装饰之后,这不是直接调用test方法,而是调用func_in方法
    test(1,2)
    • 通用装饰器的使用
    def func(fn):
        # 需要有参数,*args,**kwargs
        def func_in(*args,**kwargs):
            print("记录日志")
            print('访问方法:'+fn.__name__)
            # 需要有参数,*args,**kwargs
            xx = fn(*args,**kwargs)
            # 需要有返回值
            return xx
        return func_in
    
    
    # 待装饰函数:无参数,无返回值
    @func
    def test1():
        print("test1")
    test1()
    @func
    def test2():
        return "Hello"
    print(test2())
    @func
    def test3(a):
        print('a=%d'%a)
    test3(1)

    类方法静态方法

    • 静态方法:
      • 1.格式:在方法上面添加 @staticmethod
      • 2.参数:静态方法可以有参数也可以无参数
      • 3.应用场景:一般用于和类对象以及实例对象无关的代码。
      • 4.使用方式: 类名.类方法名(或者对象名.类方法名)
      • 使用示例: 比如:学生管理系统的展示主菜单
    • 类方法:
      • 无需实例化,可以通过类直接调用的方法,但是方法的第一个参数接收的一定是类本身
      • 1.在方法上面添加@classmethod
      • 2.方法的参数为 cls 也可以是其他名称,但是一般默认为 cls
      • 3.cls 指向 类对象(也就是 Goods)
      • 4.应用场景:当一个方法中只涉及到静态属性的时候可以使用类方法(类方法用来修改类属 性)。
      • 5.使用 可以是 对象名.类方法名。或者是 类名.类方法名
      • 使用示例:
        • 修改所有商品的折扣
        class Goods():
        discount = 1
        def __init__(self,price,name):
            self.name = name
            self.price = price
        def price_discount(self):
            return self.price * Goods.discount
        @classmethod
        def change_discount(cls,new_discount):
            cls.discount = new_discount
  • 相关阅读:
    Luogu 4206 [NOI2005]聪聪与可可
    【Luogu】P3708Koishi的数字游戏(数论)
    【Luogu】P1850换教室(期望DP)
    【Luogu】P1231教辅的组成(拆点+Dinic+当前弧优化)
    【Luogu】P3865ST表模板(ST表)
    【Luogu】P3376网络最大流模板(Dinic)
    【Luogu】P1005矩阵取数游戏(高精度+DP)
    【Luogu】P2324骑士精神(IDA*)
    【Luogu】P3052摩天大楼里的奶牛(遗传算法乱搞)
    洛森地图半成品
  • 原文地址:https://www.cnblogs.com/ilovepython/p/10951775.html
Copyright © 2011-2022 走看看