装饰器使用

44 篇文章 0 订阅
18 篇文章 1 订阅

前置认识

'''
学习装饰器,python重要特性之一;用函数修改函数
'''

# 1 函数内定义函数:只能函数内部访问

def hi(name = 'greet'):
    print('S1: Inside hi function!' )

    def greet():
        return 'now in greet function'

    def hello():
        return 'now in hello func!'

    print(greet())
    print(hello())

    print('S4: Hi func end!')

    if name == 'greet':
        return greet
    else:
        return hello

hi()

#函数名赋值给另一个名字;删除它
talk = hi
talk()
# del hi
# talk()

# 2 函数返回函数, 函数当做参数传递给函数;
fun1 = hi()
fun2 = hi('hello')
print(fun1,fun2)

def acceptFunc(func):
    print("Do sth. before hi func")

    print(func()())

acceptFunc(hi) # 先自行Do sth before hi; 再自行hi()输出,最后返回了一个函数名再次被执行,故func()()

# 总结:函数可以嵌套函数、当做参数传值给另一个函数、当做返回值返回结果

# 3 第一个装饰器:利用 "learn hard", "finallay succeed!"  wrap包装 hello decorator!
print(20 * '>>',"First decorator in python world")
def first_decorator(func):
    def wrapFunc():
        print("1st, I learn hard!")
        func()
        print("Finally succeed!")

    return wrapFunc #一定要返回,内部包裹的函数,以后面形成嵌套 @结构

def hello():
    print('Hello, decorator world! >>>>')

hello = first_decorator(hello)
hello() #这里的装饰器就好像辅助函数,帮助主体核心hello实现外在的“不重要”功能(开始、结束巴啦啦)

print("Same way using @", 10 * ">>")

@first_decorator
def hello2():
    print('Hello, short @ decorator!')

hello2()
#我们在代码里并没有使用 @ 符号?那只是一个简短的方式来生成一个被装饰的函数。这里是我们如何使用 @ 来运行之前的代码:
#@a_new_decorator 是缩写:a_func_requre_decoration = a_new_decorator(a_func_require_decoration)
print(hello2.__name__) #因为缩写那句改为first_decorator, 里面又是warp函数覆盖的

print(15 * ">>", "通过functools的wraps函数还原被装饰的函数名,作为func.__name__名称")
from functools import wraps

def second_decorator(func):
    @wraps(func) #名称进行命名反覆盖,装饰器;
    def wrapfunc():
        print("Second decorator, lucky!")
        func()
        print("Happy end!")
    return wrapfunc

@second_decorator
def hello3():
    print("Say hello too many times")

hello3()
print(hello3.__name__)
# @wraps接受一个函数来进行装饰,并加入了复制函数名称、注释文档、参数列表等等的功能。这可以让我们在装饰器里面访问在装饰之前的函数的属性。


蓝本、举例:授权、日志和类装饰器


# 4 装饰器常用场景之一:
# 蓝本
print('Give a decorator template!', 10 * '>>')
def decorater_name(f):
    @wraps(f)
    def wrapFunc():
       if not Ctrl_flag:
           return 'Will not run'
       return f()
    return wrapFunc

Ctrl_flag = True

@decorater_name
def hello4():
    return ('I am typical decorator hello')
print(hello4())

Ctrl_flag = False
print(hello4()) # hello not funcs

# 5 授权authorization
# 八股的逻辑,检查如果未授权就开始授权; 如果授权,就返回状态说已经授权;

def decorator_author(func):
    @wraps(func) #名称反覆盖、前面变量传入里面等作用
    def wrapFunc(*args, **kwargs):
        if not Author_Flag:
            return Author()
        return func(*args, **kwargs)#'Already authorized!'
    return wrapFunc

def Author():
    print("未授权:开始授权...,授权成功!")

@decorator_author
def authorFunc(*args, **kwargs):
    ls = list(args)
    di = kwargs
    print("Users:")
    [print(it) for it in args]
    print("At places of:")
    [print(k,'->', w) for (k,w) in kwargs.items()]
    print("已经成功授权")


Author_Flag = True
authorFunc('fei','cui','peng', home=True, School = True)

Author_Flag = False
authorFunc()

# 6 日志
from functools import wraps

def logger(func):
    @wraps(func)
    def func_wrap(x):
        print(func.__name__ + ' is called!')
        return func(x)
    return func_wrap

@logger
def loggingMy(x):
    print('x square:', x ** 2)

loggingMy(10)

# 7 类做装饰器,__init__传初始参数,__call__做装饰器;

class logger(object):
    def __init__(self, file = 'logging_file.txt'):
        self.file = file

    def __call__(self, func):
        @wraps(func)
        def wrapFunc(*args, **kwargs):
            str = func.__name__
            print(str + " is called!")
            with open(self.file,'w') as f:
                f.write(str)
            return func(*args, **kwargs)
        return wrapFunc

@logger()
def addArgs(*args, **kwargs):
    s = sum(* args)
    print(*kwargs, ' can count ',  str(s))

addArgs([2,3,4], Me = 50)

额外知识:内置funtools中的wraps实现

# 8 装饰器内核:wraps实现
print(10 * "<<",'探索wraps实现')

def decoratorExample(func):
    @wraps(func)
    def wrapFunc(*args, **kwargs):
        '''wrapFunc'''
        print('wrapFunc')
        return func(*args, **kwargs)
    return wrapFunc

@decoratorExample
def hello6(*args):
    '''Doc:hello 6'''
    print('hello', [a for a in args])

hello6('peng','fei')
print(hello6.__name__, hello6.__doc__)

# 实际的wraps装饰器,就是一个三层套函数的装饰器,第一层传装饰器参量func;第二层传内核函数名fwrap;第三层传内核函数的参数列表args等
def wrapsEx(func): #传参数套函
    def TmpWraps(fwrap): #实际嵌入函数套函
        def wrapFunc(*args, **kwargs): #嵌入函数的传参数套函
            wrapFunc.__name__ = func.__name__
            wrapFunc.__doc__ = func.__doc__
            return fwrap(*args, **kwargs)
        return wrapFunc
    return TmpWraps

def decoratorEx(func):
    @wrapsEx(func)  # func = wrapsEx(func) = TmpWraps
    def wrapFunc(*args, **kwargs):
        '''wrapFunc2'''
        print('wrapFunc')
        return func(*args, **kwargs) # TmpWraps() = wrapFunc
    return wrapFunc


@decoratorEx
def hello7(*args): #hello7 = decoratorEx(hello7) = wrapFunc
    '''doc:hello 7'''
    print('hello', [a for a in args])


hello7('peng2', 'fei2') # = wrapFunc() = hello7()
print(hello7.__name__, hello7.__doc__)

output

<<<<<<<<<<<<<<<<<<<< 探索wraps实现
wrapFunc
hello [‘peng’, ‘fei’]
hello6 hello 6
wrapFunc
hello [‘peng2’, ‘fei2’]
hello7 hello 7

  • 两个case: hello6和hello7输出完全一样;
  • 说明 @wraps装饰器是一个典型的3层嵌套装饰器结构,通过(func)传入函数名,通过内部的wrapFunc内核函数,将wrapFunc.__name__和__doc__由wrapFunc内容,翻转为func函数内容

总结

  • 装饰器使用函数来包裹函数(类包裹函数),完成一些统一的前置、后置处理操作,非常简洁、方便;自己成为一个体系;
  • 并且随时修改内核的(被包裹函数)的内容、功能、方式等
  • 重点使用注意:@wraps(func)用来反转name函数被覆盖弊端、传入之前函数的值、类型等
  • 重点使用注意:内部定义def wrapFunc(*args),返回两次(一次可能是内部的func执行),另一个是必须的return wrapFunc,这是函数修饰decorator函数,修改函数的关键; 内部包裹,自我实现;核心成为装饰函数的一个部分,同时又返回给内核函数名称(甘愿成为配角,凸显、服务、只为核心函数)
  • 类装饰器,适配python一切皆对象的理念,理所当然;并且通过__init__赋装饰函数值;通过__call__(func)来做正式装饰函数主体,整洁clean,易于理解。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值