zoukankan      html  css  js  c++  java
  • python装饰器@property

    装饰器示例

    def w1(func):
        def inner():
            print('...验证权限...')
            func()
    
        return inner
    
    
    @w1
    def f1():
        print('f1 called')
    
    
    @w1
    def 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
    
    
    @w1
    def test():
        print('test')
    
    test()

    输出结果:

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

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

    test = w1(test)

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

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

    输出结果:

    ----b----
    ----a----
    ----1----
    ----2----
    ----c----
    ----3----
    <b><i>hello python decorator</i></b>

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

    对有参数函数进行装饰

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

    输出结果:

    say inner called
    hello wangcai

    多个参数或不定个参数

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

    输出结果:

    add inner called
    2 + 4 = 6
    add inner called
    2 + 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_test
    def test():
        print('this is test fun')
        return 'hello'
    
    
    ret = test()
    print('ret value is %s' % ret)

    输出结果:

    w_test inner called start
    this is test fun
    w_test inner called end
    ret 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_test
    def test():
        print('this is test fun')
        return 'hello'
    
    
    ret = test()
    print('ret value is %s' % ret)

    输出结果:

    w_test inner called start
    this is test fun
    w_test inner called end
    ret 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 wangcai
    this is test log

    通用装饰器

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

    输出结果:

    test called
    test1 called
    test2 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()
    
    
    @Test
    def test():
        print('this is test func')
    
    
    test()

    输出结果:

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

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

  • 相关阅读:
    JAVA NIO 结合多线程
    ios即时通讯客户端开发之-mac上安装MySQL
    使用第三方库AFNetworking时遇到的问题
    用CocoaPods做iOS程序的依赖管理(转载)
    IOS8 设置TableView Separatorinset 分割线从边框顶端开始
    (转)UIViewController中各方法调用顺序及功能详解
    iOS中遍历数组的几种方法
    取消tableView上面多出来20个像素
    UIView动画中的一些坑
    ios build时,Undefined symbols for architecture xxx问题的总结(转)
  • 原文地址:https://www.cnblogs.com/xiaoaofengyue/p/9025180.html
Copyright © 2011-2022 走看看