python装饰器

函数装饰器

python的装饰器是个非常强大的功能,下面的部分代码借鉴stackoverflow上面的代码,是对我学习装饰器的一个梳理。
函数装饰器(function decorator)

 什么是装饰器(decorator)?
 装饰器就是任何把其他函数或者方法当做参数并且返回一个增强函数的函数被当做装饰器
 装饰器的概念可以从字面意义上面理解,就是其他函数通过@语法糖把某些装饰器的功能借用过来。

#这是一个非常简单的装饰器,它什么也没有做,但是这个就是装饰器的原型,也可以理解为语法规则。
# -*- coding:utf-8 -*-

def first_decorator(func):
    return func

@first_decorator #等同于my_functions = first_decorator(my_function)
def my_function():
    print("a simple test decorator")

if __name__ == '__main__':
    my_function()
#output:
#a simple test decorator

 如何才能理解一个装饰器呢?很简单,让我们看看如果破坏这种‘语法糖’的话会发生什么?

# -*- coding:utf-8 -*-

def second_decorator(func):
    pass #装饰器没有返回一个函数

@second_decorator
def my_function():
    print("what will happend?")

if __name__ == '__main__':
    my_function()
#output
#TypeError: 'NoneType' object is not callable #返回一个错误

那么我们一般是如何使用一个装饰器的呢?使用一个两层嵌套,看看下面这个例子:

# -*- coding:utf-8 -*-

def logger(func):
    def wrapper(*args, **kwargs):
        print("calling {0}".format(func.__name__)) #__name__方法是输出函数的名字
        return func(*args, **kwargs) #最后输出的是原始函数
    return wrapper #返回后代替logger成为装饰器

@logger #装饰器的使用
def get_args(*args, **kwargs):
    print("*args={0}, **kwargs={1}".format(*args,**kwargs))

if __name__ == '__main__':
    get_args('hello','world')
#output
#calling get_args
#*args=hello, **kwargs=world

 上面我们看到的装饰器的参数都是函数,这个是默认的装饰器的特性,那么如果我想在装饰器中加入其他的参数怎么办?我们需要使用一个三层嵌套。

#这个装饰器没有什么特别的含义,只是展示一下装饰器工作的过程,我们可以自己想装饰器中输入参数而不需要借助被装饰函数操作
# -*- coding:utf-8 -*-

def logger(text):
    def decorator(func):
        def wrapper(*args,**kwargs):
           print("*args={0}, **kwargs={1}".format(*args, **kwargs))
            print("{1} calling {0}".format(func.__name__, text))
            return func(*args,**kwargs)
        return wrapper
    return decorator

@logger("sys")
def get_args(*args, **kwargs):
    print("*args={0}, **kwargs={1}".format(*args,**kwargs))

if __name__ == '__main__':
    get_args("chuan","cong")
    print("func.name = {0}".format(get_args.__name__))
#output
#*args=chuan, **kwargs=cong
#sys calling get_args
#*args=chuan, **kwargs=cong
#func.name = wrapper #这里的输出说明函数经过装饰器装饰之后函数吗已经变成了最后装饰它的那个函数的名称,这样是很容易出问题的,在一些需要函数前面的代码中,我们应该解决这个问题。

 如何制止装饰器修改被装饰函数的函数名呢?只需要functools模块即可

# -*- coding:utf-8 -*-
import functools

def logger(text):
    def decorator(func):
        @functools.wraps(func) #我们只需要在装饰器最后一个函数的前面加上这个装饰器即可,这个是模块自带的
        def wrapper(*args,**kwargs):
            print("*args={0}, **kwargs={1}".format(*args, **kwargs))
            print("{1} calling {0}".format(func.__name__, text))
            return func(*args,**kwargs)
        return wrapper
    return decorator

@logger("sys")
def get_args(*args, **kwargs):
    print("*args={0}, **kwargs={1}".format(*args,**kwargs))


if __name__ == '__main__':
    get_args("chuan","cong")
    print("func.name = {0}".format(get_args.__name__))
#output
#*args=chuan, **kwargs=cong
#sys calling get_args
#*args=chuan, **kwargs=cong
#func.name = get_args #看,已经被修改过来了

类装饰器

 什么是类装饰器?函数装饰器是形如:my_function=decorator(my_function),那么类呢?形式和函数装饰器差不多,但是实现过程由细微的差别。

class Decorator(object):#类装饰器的构建

    def __init__(self, func): #初始化是把被装饰函数当做参数,赋予对象
        self.func = func 

    def __call__(self, *args, **kwargs):
        print('Before the function call.')
        res = self.func(*args, **kwargs) #调用函数
        print('After the function call.')
        return res

@Decorator
def testfunc():
    print('Inside the function.')
    print('xue')

testfunc()
print(type(testfunc))
#output
#Before the function call.
#Inside the function.#函数调用输出
#xue
#After the function call.
#<class 'dec_test2.Decorator'> #被装饰函数类型改变

函数装饰器和类装饰器由什么不同呢?
类装饰器中被装饰函数只有被调用时才会执行,否则不会执行,但是函数装饰器在装饰完成后会在最后执行。
 同样,类装饰器在装饰函数之后,被装饰的函数类型会发生改变,变成了类。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值