码迷,mamicode.com
首页 > 编程语言 > 详细

python进阶之装饰器之2.定义一个可接受参数的装饰器、如何定义一个属性可由用户修改的装饰器、定义一个能接受可选参数的装饰器

时间:2018-07-21 22:51:03      阅读:254      评论:0      收藏:0      [点我收藏+]

标签:rate   *args   操作   装饰器   local   icc   critical   efault   imp   

2.1.定义一个接受参数的装饰器

前言:在理解上一篇文章的基础上理解定义一个接受参数的装饰器

思路:在装饰器函数的外层再定义一个接受参数的函数,让他返回装饰器函数,在装饰器函数中进行相关参数的进行操作

代码解析如下:

from functools import wraps
import logging
# 定义外层函数logged,使用return decorate返回装饰器函数
def logged(level, name=None, message=None):
"""
Add logging to a function. level is the logging
level, name is the logger name, and message is the
log message. If name and message aren‘t specified,
they default to the function‘s module and name.
"""
# 定义一个装饰器,返回wrapper函数
def decorate(func):
# 对传入的参数进行相关操作
logname = name if name else func.__module__
print(logname)
log = logging.getLogger(logname)
print(log)
logmsg = message if message else func.__name__
print(logmsg)

@wraps(func)
# 定义wrapper函数,返回被装饰的func函数,即后面示例中的add函数或者spam函数
def wrapper(*args, **kwargs):
log.log(level, logmsg)
return func(*args, **kwargs)
return wrapper
return decorate

# Example use
@logged(logging.DEBUG)
def add(x, y):
return x + y

print(add(2,5))

输出:

__main__
<Logger __main__ (WARNING)>
add
7

 



@logged(logging.CRITICAL, ‘example‘)
def spam():
print(‘Spam!‘)

print(spam())
输出:

example
<Logger example (WARNING)>
spam
Spam!

None              #若def函数后面追加一个return “hello”,则最后一个None改为hello

 

小结:

@decorator(x, y, z)
def func(a, b):
    pass

装饰器处理过程跟下面的调用是等效的;

def func(a, b):
    pass
func = decorator(x, y, z)(func)

2.2  如何定义一个属性可由用户修改的装饰器

前言:定义一个可以传参数的装饰器,若现在需要给以动态修改装饰器的属性,改若何定义呢?

思路:此处使用访问器函数(accessor function),然后nonlocal 来修改内部变量

代码解析如下:

from functools import wraps, partial
import logging

# Utility decorator to attach a function as an attribute of obj
def attach_wrapper(obj, func=None):
    if func is None:
        return partial(attach_wrapper, obj)
    setattr(obj, func.__name__, func)
    return func

def logged(level, name=None, message=None):
    ‘‘‘
    Add logging to a function. level is the logging
    level, name is the logger name, and message is the
    log message. If name and message aren‘t specified,
    they default to the function‘s module and name.
    ‘‘‘
    def decorate(func):
        logname = name if name else func.__module__
        log = logging.getLogger(logname)
        logmsg = message if message else func.__name__

        @wraps(func)
        def wrapper(*args, **kwargs):
            log.log(level, logmsg)
            return func(*args, **kwargs)

        # Attach setter functions
        @attach_wrapper(wrapper)
        def set_level(newlevel):
            nonlocal level
            level = newlevel

        @attach_wrapper(wrapper)
        def set_message(newmsg):
            nonlocal logmsg
            logmsg = newmsg
        return wrapper
    return decorate


# Example use
@logged(logging.DEBUG)
def add(x, y):
    return x + y

@logged(logging.CRITICAL, example)
def spam():
    print(Spam!)



# level级别默认设置为DEBUG
logging.basicConfig(level=logging.DEBUG)
print(add(2, 3))
# DEBUG:__main__:add
# 5


# Change the log message
add.set_message(Add called)
print(add(2, 3))
# DEBUG:__main__:Add called
# 5


# Change the log level
add.set_level(logging.WARNING)
print(add(2, 3))
# WARNING:__main__:Add called
# 5


若使用其他对于属性直接访问的方法,只能访问到顶层装饰器,例如:
@timethis
@logged(logging.DEBUG)
def countdown(n):
    while n > 0:
        n -= 1
其中顶层装饰器函数为:@timethis,用直接访问属性的方法会失败,请记住这点

本小节的内容可以作为后续类装饰器的替代
 

 

python进阶之装饰器之2.定义一个可接受参数的装饰器、如何定义一个属性可由用户修改的装饰器、定义一个能接受可选参数的装饰器

标签:rate   *args   操作   装饰器   local   icc   critical   efault   imp   

原文地址:https://www.cnblogs.com/max520liuhu/p/9348077.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!