zoukankan      html  css  js  c++  java
  • Python生成器、装饰器

    ## 生成器
      - 生成器是用来创建Python序列的一个对象
      - 通常生成器是为迭代器产生数据的
      - 例如range()函数就是一个生成器
      - 每次迭代生成器时,它都会记录上一次调用的位置,并返回下一个值,这使程序不需要创建和存储完整的序列

    ## 生成器函数
      - 生成器函数与普通函数类似,但它的返回值使用yield语句,而不是return

     1 def my_range(start=0, last=10, step=1):
     2     number = start
     3     while number < last:
     4         yield number
     5         number += step
     6     
     7 my_range     # 是一个普通函数
     8 # <function my_range at 0x7efe3dbf2e18>
     9 
    10 my_range()   # 返回一个生成器对象
    11 # <generator object my_range at 0x7efe3daac360>
    12 
    13 list(my_range(1, 10))
    14 # [1, 2, 3, 4, 5, 6, 7, 8, 9]          

    ## 装饰器

      - 装饰器的作用在于在不改变原有代码结构的前提下,对原有代码的功能进行补充扩展
      - 装饰器的本质上是接受函数为参数的高阶函数,它把一个函数作为参数输入并且返回一个功能拓展后的新函数

     1 # 装饰器函数,为函数添加两条语句
     2 def deco(fn):
     3     def new_func(*args):  # 内部函数的参数需要与传入的fn的参数相同
     4         print("执行函数:{0}".format(fn.__name__))
     5         result = fn(*args)
     6         print("函数执行结果:{0}".format(result))
     7         return result
     8     return new_func
     9 
    10 
    11 @deco    # 使用@装饰函数名,使用装饰器之后,add实际上已经指向了doco函数返回的新函数
    12 def add(*args):
    13     print("我是核心代码,可不能改动我")
    14     result = 0
    15     for n in args:
    16         result += n
    17     return result
    18 
    19 
    20 add(1, 2, 3, 4)
    21 """
    22 执行结果:
    23     执行函数:add
    24     我是核心代码,可不能改动我
    25     函数执行结果:10
    26 """

        

        - 一个函数可以有多个装饰器

        - 最靠近函数的装饰器会先执行,然后一次向上执行装饰器

     1 def count_param(fn):
     2     def new_func(*args):
     3         amount = len(args)
     4         fn(*args)
     5         print("参数个数为:{0}".format(amount))
     6         return amount
     7     return new_func
     8 
     9 
    10 @count_param
    11 @deco
    12 def add(*args):
    13     print("我是核心代码,可不能改动我")
    14     result = 0
    15     for n in args:
    16         result += n
    17     return result
    18 
    19 
    20 add(1, 2, 3, 4)
    21 """
    22 执行结果:
    23     执行函数:add
    24     我是核心代码,可不能改动我
    25     函数执行结果:10
    26     参数个数为:4
    27 """

        - 如果decorator本身需要传入参数,那就需要编写一个返回decorator的高阶函数

     1 import time
     2 
     3 
     4 def log(now_time):
     5     def deco(fn):
     6         def new_func(*args, **kwargs):
     7             print(now_time)
     8             return fn(*args, **kwargs)
     9         return new_func
    10     return deco
    11 
    12 
    13 @log(time.asctime(time.localtime(time.time())))
    14 def add(*args):
    15     print("我是核心代码,可不能改动我")
    16     result = 0
    17     for n in args:
    18         result += n
    19     return result
    20 
    21 
    22 add(1, 2, 3, 4)
    23 """
    24 执行结果:
    25     函数开始时间:Sun Jul  1 15:30:14 2018
    26     我是核心代码,可不能改动我
    27 """

      - 此时打印add函数的__name__属性发现:

    print("核心函数名:{0}".format(add.__name__))
    """
    输出:
        核心函数名:new_func
    """

      

      - 这表明虽然装饰器表面上并没有改变核心函数的内容,但实际上还是对核心函数的属性进行了修改,所以还需要将核心函数的__name__属性复制到新函数

     1 import time
     2 
     3 
     4 def log(now_time):
     5     def deco(fn):
     6         def new_func(*args, **kwargs):
     7             # 将原函数的__name__属性复制到新函数
     8             new_func.__name__ = fn.__name__
     9             print(now_time)
    10             return fn(*args, **kwargs)
    11         return new_func
    12     return deco
    13 
    14 
    15 @log(time.asctime(time.localtime(time.time())))
    16 def add(*args):
    17     print("我是核心代码,可不能改动我")
    18     result = 0
    19     for n in args:
    20         result += n
    21     return result
    22 
    23 
    24 add(1, 2, 3, 4)
    25 print("核心函数名:{0}".format(add.__name__))
    26 """
    27 执行结果:
    28     Sun Jul  1 15:43:00 2018
    29     我是核心代码,可不能改动我
    30     核心函数名:add
    31 """    

      - 在functools里面有一个专门的函数处理这个问题

     1 import time
     2 import functools
     3 
     4 
     5 def log(now_time):
     6     def deco(fn):
     7         @functools.wraps(fn)      # 在新的函数上添加装饰器,修改新函数的__name__属性
     8         def new_func(*args, **kwargs):
     9             print(now_time)
    10             return fn(*args, **kwargs)
    11         return new_func
    12     return deco
    13 
    14 
    15 @log(time.asctime(time.localtime(time.time())))
    16 def add(*args):
    17     print("我是核心代码,可不能改动我")
    18     result = 0
    19     for n in args:
    20         result += n
    21     return result
    22 
    23 
    24 add(1, 2, 3, 4)
    25 print("核心函数名:{0}".format(add.__name__))
    26 ”“”
    27 执行结果:
    28     Sun Jul  1 15:48:10 2018
    29     我是核心代码,可不能改动我
    30     核心函数名:add
    31 “”“

      - 类装饰器 

     1 class Test(object):
     2     def __init__(self, fn):
     3         self.fn = fn
     4 
     5     # 重写__call__函数,使实例能够像函数一样调用
     6     def __call__(self, *args, **kwargs):
     7         print("这是基于类的修饰")
     8         return self.fn(*args, **kwargs)
     9 
    10 
    11 @Test
    12 def core_func(a, b):
    13     return a + b
    14 
    15 
    16 print(core_func(2, 3))
    17 """
    18 输出:
    19     这是基于类的修饰
    20     5
    21 """

      - 类装饰器带参数

     1 import datetime
     2 import functools
     3 
     4 
     5 class Test(object):
     6     def __init__(self, log):
     7         self.log = log
     8 
     9     # 重写__call__函数,使实例能够向函数一样调用
    10     def __call__(self, fn):
    11         @functools.wraps(fn)    # 同样在这里使用functools.wraps(),将原函数__name__属性复制到新函数
    12         def wrapper(*args, **kwargs):
    13             print(self.log)
    14             print("执行函数:%s" % fn.__name__)
    15             return fn(*args, **kwargs)
    16         return wrapper
    17 
    18 
    19 @Test(datetime.datetime.now())
    20 def core_func(a, b):
    21     return a + b
    22 
    23 
    24 @Test(datetime.datetime.now())
    25 def say_hi():
    26     print("Hi")
    27 
    28 
    29 print(core_func(2, 3))
    30 print(core_func.__name__)   # 输出:core_func
    31 say_hi()
    32 print(say_hi.__name__)      # 输出:say_hi
    33 """
    34 输出:
    35     2018-07-02 10:55:27.258637
    36     执行函数:core_func
    37     5
    38     core_func
    39     2018-07-02 10:55:27.258696
    40     执行函数:say_hi
    41     Hi
    42     say_hi
    43 """

    本文参考:

      [美]Bill Lubanovic 《Python语言及其应用》
      https://www.liaoxuefeng.com 廖雪峰的官方网站 

  • 相关阅读:
    android selector shape 使用
    android AES 加密解密
    TabLayout+ViewPager 标题不显示问题
    BottomNavigationView 使用
    greendao3.2.0使用
    android studio svn不显示问题
    scrapy爬虫学习系列五:图片的抓取和下载
    scrapy爬虫学习系列四:portia的学习入门
    scrapy爬虫学习系列二:scrapy简单爬虫样例学习
    scrapy爬虫学习系列一:scrapy爬虫环境的准备
  • 原文地址:https://www.cnblogs.com/hycstar/p/9250403.html
Copyright © 2011-2022 走看看