博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
python装饰器@property
阅读量:5339 次
发布时间:2019-06-15

本文共 4470 字,大约阅读时间需要 14 分钟。

装饰器示例

def w1(func):    def inner():        print('...验证权限...')        func()    return inner@w1def f1():    print('f1 called')@w1def f2():    print('f2 called')f1()f2()

输出结果:

...验证权限...f1 called...验证权限...f2 called

当调用f1,f2函数时,首先执行了验证。通过一个闭包函数w1,调用函数上通过关键词@w1,对f1,f2完成了装饰。

当python解释器解释@w1时,会调用w1函数,同时将被修饰函数名传入(例如f1),在执行w1函数的时候,直接把inner函数返回了,同事把它赋值给f1,此时的f1已经不是未加修饰的f1了,而是指向了w1.inner函数地址。再调用f1函数,就好先执行权限验证,然后调用原来的f1(),该处的f1是通过参数传进来的f1.

执行时机

def w1(fun):    print('...装饰器开始装饰...')    def inner():        print('...验证权限...')        fun()    return inner@w1def test():    print('test')test()

输出结果:

...装饰器开始装饰......验证权限...test

由此可见,执行@w1时相当于执行了如下代码:

test = w1(test)

两个装饰器执行流程和修饰结果

def makeBold(fun):    print('----a----')    def inner():        print('----1----')        return '' + fun() + ''    return innerdef makeItalic(fun):    print('----b----')    def inner():        print('----2----')        return '' + fun() + ''    return inner@makeBold@makeItalicdef test():    print('----c----')    print('----3----')    return 'hello python decorator'ret = test()print(ret)

输出结果:

----b--------a--------1--------2--------c--------3----hello python decorator

可以发现,先用第二个装饰器(makeItalic)进行装饰,接着再用第一个装饰器(makeBold)进行装饰,而在调用过程中,先执行第一个装饰器(makeBold),接着再执行第二个装饰器(makeItalic)。

对有参数函数进行装饰

def w_say(fun):    """    如果原函数有参数,那闭包函数必须保持参数个数一致,并且将参数传递给原方法    """    def inner(name):        """        如果被装饰的函数有行参,那么闭包函数必须有参数        :param name:        :return:        """        print('say inner called')        fun(name)    return inner@w_saydef hello(name):    print('hello ' + name)hello('wangcai')

输出结果:

say inner calledhello wangcai

多个参数或不定个参数

def w_add(func):    def inner(*args, **kwargs):        print('add inner called')        func(*args, **kwargs)    return inner@w_adddef add(a, b):    print('%d + %d = %d' % (a, b, a + b))@w_adddef add2(a, b, c):    print('%d + %d + %d = %d' % (a, b, c, a + b + c))add(2, 4)add2(2, 4, 6)

输出结果:

add inner called2 + 4 = 6add inner called2 + 4 + 6 = 12

对带返回值的函数进行修饰

def w_test(func):    def inner():        print('w_test inner called start')        func()        print('w_test inner called end')    return inner@w_testdef test():    print('this is test fun')    return 'hello'ret = test()print('ret value is %s' % ret)

输出结果:

w_test inner called startthis is test funw_test inner called endret value is None

可以发现,此时,并没有输出test函数的‘hello’,而是None,那是为什么呢,可以发现,在inner函数中对test进行了调用,但是没有接受不了返回值,也没有进行返回,那么默认就是None了,知道了原因,那么来修改一下代码:

def w_test(func):    def inner():        print('w_test inner called start')        str = func()        print('w_test inner called end')        return str    return inner@w_testdef test():    print('this is test fun')    return 'hello'ret = test()print('ret value is %s' % ret)

输出结果:

w_test inner called startthis is test funw_test inner called endret value is hello

带参数的装饰器

def func_args(pre='xiaoqiang'):    def w_test_log(func):        def inner():            print('...记录日志...visitor is %s' % pre)            func()        return inner    return w_test_log# 带有参数的装饰器能够起到在运行时,有不同的功能# 先执行func_args('wangcai'),返回w_test_log函数的引用# @w_test_log# 使用@w_test_log对test_log进行装饰@func_args('wangcai')def test_log():    print('this is test log')test_log()

输出结果:

...记录日志...visitor is wangcaithis is test log

通用装饰器

def w_test(func):    def inner(*args, **kwargs):        ret = func(*args, **kwargs)        return ret    return inner@w_testdef test():    print('test called')@w_testdef test1():    print('test1 called')    return 'python'@w_testdef test2(a):    print('test2 called and value is %d ' % a)test()test1()test2(9)

输出结果:

test calledtest1 calledtest2 called and value is 9

类装饰器

装饰器函数其实是一个接口约束,它必须接受一个callable对象作为参数,然后返回一个callable对象。

在python中,一般callable对象都是函数,但是也有例外。比如只要某个对象重写了call方法,那么这个对象就是callable的。

当创建一个对象后,直接去执行这个对象,那么是会抛出异常的,因为他不是callable,无法直接执行,但进行修改后,就可以直接执行调用了,如下

class Test(object):    def __call__(self, *args, **kwargs):        print('call called')t = Test()print(t())

下面,引入正题,看一下如何用类装饰函数。

class Test(object):    def __init__(self, func):        print('test init')        print('func name is %s ' % func.__name__)        self.__func = func    def __call__(self, *args, **kwargs):        print('装饰器中的功能')        self.__func()@Testdef test():    print('this is test func')test()

输出结果:

test initfunc name is test 装饰器中的功能this is test func

和之前的原理一样,当python解释器执行到到@Test时,会把当前test函数作为参数传入Test对象,调用init方法,同时将test函数指向创建的Test对象,那么在接下来执行test()的时候,其实就是直接对创建的对象进行调用,执行其call方法。

 

转载于:https://www.cnblogs.com/xiaoaofengyue/p/9025180.html

你可能感兴趣的文章
一个.NET通用JSON解析/构建类的实现(c#)
查看>>
Windows Phone开发(5):室内装修 转:http://blog.csdn.net/tcjiaan/article/details/7269014
查看>>
详谈js面向对象 javascript oop,持续更新
查看>>
关于这次软件以及pda终端的培训
查看>>
jQuery上传插件Uploadify 3.2在.NET下的详细例子
查看>>
如何辨别一个程序员的水平高低?是靠发量吗?
查看>>
新手村之循环!循环!循环!
查看>>
正则表达式的用法
查看>>
线程安全问题
查看>>
SSM集成activiti6.0错误集锦(一)
查看>>
下拉刷新
查看>>
linux的子进程调用exec( )系列函数
查看>>
MSChart的研究
查看>>
C# 索引器
查看>>
MySQLdb & pymsql
查看>>
zju 2744 回文字符 hdu 1544
查看>>
delphi 内嵌汇编例子
查看>>
【luogu P2298 Mzc和男家丁的游戏】 题解
查看>>
前端笔记-bom
查看>>
MATLAB作图方法与技巧(一)
查看>>