zoukankan      html  css  js  c++  java
  • 学习笔记-装饰器

    一. 知识铺垫

    函数嵌套:

     1 def hi(name="yasoob"):
     2     def greet():
     3         return "now you are in the greet() function"
     4  
     5     def welcome():
     6         return "now you are in the welcome() function"
     7  
     8     if name == "yasoob":
     9         return greet
    10     else:
    11         return welcome
    12  
    13 a = hi()
    14 print(a)
    15 #outputs: <function greet at 0x7f2143c01500>
    16  
    17 #上面清晰地展示了`a`现在指向到hi()函数中的greet()函数
    18 #现在试试这个
    19  
    20 print(a())
    21 #outputs: now you are in the greet() function
    View Code

    函数作为参数:

     1 def hi():
     2     return "hi yasoob!"
     3  
     4 def doBeforeHi(func):
     5     print("I am doing some boring work before executing hi()")
     6     print(func())
     7  
     8 doBeforeHi(hi)
     9 #outputs:I am doing some boring work before executing hi()
    10 #        hi yasoob!
    View Code

     二. 装饰器

    1.概念

      装饰器是修改函数功能的函数

     1 def a_new_decorator(a_func):
     2  
     3     def wrapTheFunction():
     4         print("I am doing some boring work before executing a_func()")
     5  
     6         a_func()
     7  
     8         print("I am doing some boring work after executing a_func()")
     9  
    10     return wrapTheFunction
    11  
    12 def a_function_requiring_decoration():
    13     print("I am the function which needs some decoration to remove my foul smell")
    14  
    15 a_function_requiring_decoration()
    16 #outputs: "I am the function which needs some decoration to remove my foul smell"
    17  
    18 a_function_requiring_decoration = a_new_decorator(a_function_requiring_decoration)
    19 #now a_function_requiring_decoration is wrapped by wrapTheFunction()
    20  
    21 a_function_requiring_decoration()
    22 #outputs:I am doing some boring work before executing a_func()
    23 #        I am the function which needs some decoration to remove my foul smell
    24 #        I am doing some boring work after executing a_func()
    View Code

       使用@符号生成被装饰函数

     1 @a_new_decorator
     2 def a_function_requiring_decoration():
     3     print("I am the function which needs some decoration to remove my foul smell")
     4  
     5 a_function_requiring_decoration()
     6 #outputs: I am doing some boring work before executing a_func()
     7 #         I am the function which needs some decoration to remove my foul smell
     8 #         I am doing some boring work after executing a_func()
     9  
    10 #the @a_new_decorator is just a short way of saying:
    11 a_function_requiring_decoration = a_new_decorator(a_function_requiring_decoration)
    View Code

      问题:打印被装饰函数名,会发现函数"a_function_requiring_decoration"被函数“warpTheFunction”代替了,即装饰器重写了原函数的名字和注释文档。

    1 print(a_function_requiring_decoration.__name__)
    2 # Output: wrapTheFunction
    View Code

      解决方法:使用functools.wraps函数

     1 from functools import wraps
     2  
     3 def a_new_decorator(a_func):
     4     @wraps(a_func)
     5     def wrapTheFunction():
     6         print("I am doing some boring work before executing a_func()")
     7         a_func()
     8         print("I am doing some boring work after executing a_func()")
     9     return wrapTheFunction
    10  
    11 @a_new_decorator
    12 def a_function_requiring_decoration():
    13     print("I am the function which needs some decoration to remove my foul smell")
    14  
    15 print(a_function_requiring_decoration.__name__)
    16 # Output: a_function_requiring_decoration
    View Code

     2. 带参数的装饰器

      在装饰器函数上加一层“带参数的包裹函数”

     1 from functools import wraps
     2  
     3 def logit(logfile='out.log'):
     4     def logging_decorator(func):
     5         @wraps(func)
     6         def wrapped_function(*args, **kwargs):
     7             log_string = func.__name__ + " was called"
     8             print(log_string)
     9             # 打开logfile,并写入内容
    10             with open(logfile, 'a') as opened_file:
    11                 # 现在将日志打到指定的logfile
    12                 opened_file.write(log_string + '
    ')
    13             return func(*args, **kwargs)
    14         return wrapped_function
    15     return logging_decorator
    16  
    17 @logit()
    18 def myfunc1():
    19     pass
    20  
    21 myfunc1()
    22 # Output: myfunc1 was called
    23 # 现在一个叫做 out.log 的文件出现了,里面的内容就是上面的字符串
    24  
    25 @logit(logfile='func2.log')
    26 def myfunc2():
    27     pass
    28  
    29 myfunc2()
    30 # Output: myfunc2 was called
    31 # 现在一个叫做 func2.log 的文件出现了,里面的内容就是上面的字符串
    View Code

      装饰器执行顺序:logit() ——> @logging_decorator ——> wrapped_function() ——> func() 即 myfunc1()/myfunc2() 

    3.装饰器类

      在装饰器的功能上加上类的“继承”优势,可以在子类中实现“新功能”,该“新功能”会被装饰到目标函数上。

      以装饰器类的方式重构logit()

     1 from functools import wraps
     2  
     3 class logit(object):
     4     def __init__(self, logfile='out.log'):
     5         self.logfile = logfile
     6  
     7     def __call__(self, func):
     8         @wraps(func)
     9         def wrapped_function(*args, **kwargs):
    10             log_string = func.__name__ + " was called"
    11             print(log_string)
    12             # 打开logfile并写入
    13             with open(self.logfile, 'a') as opened_file:
    14                 # 现在将日志打到指定的文件
    15                 opened_file.write(log_string + '
    ')
    16             # 现在,发送一个通知
    17             self.notify()
    18             return func(*args, **kwargs)
    19         return wrapped_function
    20  
    21     def notify(self):
    22         # logit只打日志,不做别的
    23         pass
    View Code

      给logit创建子类,添加发送Email功能

     1 class email_logit(logit):
     2     '''
     3     一个logit的实现版本,可以在函数调用时发送email给管理员
     4     '''
     5     def __init__(self, email='admin@myproject.com', *args, **kwargs):
     6         self.email = email
     7         super(email_logit, self).__init__(*args, **kwargs)
     8  
     9     def notify(self):
    10         # 发送一封email到self.email
    11         # 这里就不做实现了
    12         pass
    View Code

    4.类装饰器

    5.使用场景

    • 授权:
     1 from functools import wraps
     2  
     3 def requires_auth(f):
     4     @wraps(f)
     5     def decorated(*args, **kwargs):
     6         auth = request.authorization
     7         if not auth or not check_auth(auth.username, auth.password):
     8             authenticate()
     9         return f(*args, **kwargs)
    10     return decorated
    View Code
    • 日志:
     1 from functools import wraps
     2  
     3 def logit(func):
     4     @wraps(func)
     5     def with_logging(*args, **kwargs):
     6         print(func.__name__ + " was called")
     7         return func(*args, **kwargs)
     8     return with_logging
     9  
    10 @logit
    11 def addition_func(x):
    12    """Do some math."""
    13    return x + x
    14  
    15  
    16 result = addition_func(4)
    17 # Output: addition_func was called
    View Code
    • 多种参数:

    参考资料:

      https://www.runoob.com/w3cnote/python-func-decorators.html

  • 相关阅读:
    C++ set简介及简单应用
    windows下安装scrapy报错:building 'twisted.test.raiser' extension error: Microsoft Visual C++ 14.0 is required.
    jsp调用Python脚本存取文件
    mysql触发器问题
    javascript调用alert()
    jsp调用Python
    注意细节,注意细节,注意细节
    pandas读取csv文件报错
    [kuangbin带你飞]专题四 最短路练习
    计算机网络之网络应用(应用层)上
  • 原文地址:https://www.cnblogs.com/jason-notbook/p/15499659.html
Copyright © 2011-2022 走看看