zoukankan      html  css  js  c++  java
  • 闭包、装饰器

    闭包:如果一个内部函数,对在外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就被认为是闭包(closure)。

      闭包 = 内部函数 + 定义函数时的环境

     1 def outer(x):
     2     def inner():  # 条件1 inner就是内部函数
     3         print(x)  # 条件2 外部环境的一个变量
     4     
     5     return inner  # 结论:内部函数inner就是一个闭包
     6 
     7 
     8 # inner()  # 1 局部变量,全局无法调用
     9 
    10 f = outer(8)  # 闭包就是一种能够调用内部函数的现象。
    11 f()

    开放封闭原则:对修改封闭,对扩展开放。

    函数装饰器:

      无参函数:

     1 import time
     2 
     3 def show_time(f):
     4     def inner():
     5         start = time.time()
     6         f()
     7         end = time.time()
     8         print('spend %s' % (end - start))
     9     return inner
    10 
    11 @show_time  # foo=show_time(foo)
    12 def foo():
    13     print('foo....')
    14     time.sleep(2)
    15 
    16 foo()

       有参函数:

     1 import time
     2 
     3 def show_time(f):
     4     def inner(x, y):
     5         start = time.time()
     6         f(x, y)  # 执行原函数(foo)
     7         end = time.time()
     8         print('spend %s' % (end - start))
     9     return inner
    10 
    11 @show_time  # foo=show_time(foo)
    12 def foo(a, b):
    13     print(a + b)
    14     time.sleep(2)
    15 
    16 # 之前调用foo时执行foo里的代码,加上装饰器后调用foo会执行inner中的代码,inner中的f就是foo,参数要一一对应。
    17 foo(3, 5)

      有参装饰器:

     1 import time
     2 
     3 def logger(flag=False):
     4     def show_time(f):
     5         def inner(x, y):
     6             start = time.time()
     7             f(x, y)  # 执行原函数(foo)
     8             end = time.time()
     9             print('spend %s' % (end - start))
    10 
    11             if flag:
    12                 print('打印日志')
    13         return inner
    14     return show_time
    15 
    16 @logger(True)  # 相当于@show_time,与上例的区别仅在于多了一个参数
    17 def foo(a, b):
    18     print(a + b)
    19     time.sleep(2)
    20 
    21 # 之前调用foo时执行foo里的代码,加上装饰器后调用foo会执行inner中的代码,inner中的f就是foo,参数要一一对应。
    22 foo(3, 5)

      嵌套装饰器:

     1 def makebold(fn):
     2     print('bold')
     3     def wrapper2():
     4         return "<b>" + fn() + "</b>"    # fn=wapper1
     5         # print("<b>" + fn() + "</b>")  # fn=wapper1
     6     return wrapper2
     7 
     8 def makeitalic(fn):
     9     print('italic')
    10     def wrapper1():
    11         return "<i>" + fn() + "</i>"  # fn=hello
    12         #  这里必须使用return,不能使用print,因为print("<b>" + None + "</b>")报错
    13         # print("<i>" + fn() + "</i>")
    14     return wrapper1
    15 
    16 @makebold  # wapper1=makebold(wapper1) --> wapper2  步骤2
    17 @makeitalic  # hello=makeitalic(hello) --> wapper1  步骤1
    18 def hello():
    19     return "hello decorater"
    20 
    21 s = hello()
    22 print(s)
    23 # italic
    24 # bold
    25 # <b><i>hello decorater</i></b>
    26 
    27 # print("<b>" + None + "</b>")  # 报错

    类装饰器:

     1 import time
     2 
     3 class Foo(object):
     4     def __init__(self, func):
     5         self._func = func
     6 
     7     def __call__(self):
     8         start_time = time.time()
     9         self._func()
    10         end_time = time.time()
    11         print('spend %s' % (end_time-start_time))
    12 
    13 @Foo  #bar=Foo(bar)
    14 def bar():
    15     print('bar')
    16     time.sleep(2)
    17 
    18 bar()  # 调用__call__方法

      使用装饰器极大地复用了代码,但有一个缺点就是原函数的元信息丢失了,比如docstring、__name__,参数列表等。

     1 def foo():
     2     print("hello foo")
     3 
     4 print(foo.__name__)
     5 #####################
     6 
     7 def logged(func):
     8     def wrapper(*args, **kwargs):
     9         print(func.__name__ + " was called")
    10         return func(*args, **kwargs)
    11     return wrapper
    12 
    13 @logged  # cal=logged(cal) --> wapper
    14 def cal(x):
    15    return x + x * x
    16 
    17 print(cal.__name__)
    18 ########
    19 # foo
    20 # wrapper  # 原函数信息丢失

      补救措施:

        functools.waps,把原函数的元信息拷贝到装饰器函数中。

     1 from functools import wraps
     2 
     3 def logged(func):
     4     @wraps(func)
     5     def wrapper(*args, **kwargs):
     6         print(func.__name__ + " was called")
     7         return func(*args, **kwargs)
     8     return wrapper
     9 
    10 @logged  # cal=logged(cal) --> wapper
    11 def cal(x):
    12    return x + x * x
    13 
    14 print(cal.__name__)
    15 # cal

    参考:http://www.cnblogs.com/yuanchenqi/articles/5830025.html

  • 相关阅读:
    测试的种类
    软件测试的原则
    软件测试的目的
    软件测试的对象
    软件的分类
    软件测试
    mysql 视图
    mysql 字段添加以及删除
    mysql 引擎类型
    mysql 数据插入insert
  • 原文地址:https://www.cnblogs.com/yangxiaoling/p/6901581.html
Copyright © 2011-2022 走看看