Python Decorators(二):Decorator参数【转载】

原文链接:http://blog.csdn.net/beckel/article/details/3945147


回顾:不含参数的decorators

在前文中,我介绍了如何使用不含参数的decorators,并使用类来实现。因为我发现这样做更容易接受。

如果创建了一个无参decorator,被decorated的函数被传至构造器,每次调用decorated函数时就会调用__call__()方法:

 class decoratorWithoutArguments(object):

 

    def __init__(self, f):

        """

        If there are no decorator arguments, the function

        to be decorated is passed to the constructor.

        """

        print "Inside __init__()"

        self.f = f

 

    def __call__(self, *args):

        """

        The __call__ method is not called until the

        decorated function is called.

        """

        print "Inside __call__()"

        self.f(*args)

        print "After self.f(*args)"

 

@decoratorWithoutArguments

def sayHello(a1, a2, a3, a4):

    print 'sayHello arguments:', a1, a2, a3, a4

 

print "After decoration"

 

print "Preparing to call sayHello()"

sayHello("say", "hello", "argument", "list")

print "After first sayHello() call"

sayHello("a", "different", "set of", "arguments")

print "After second sayHello() call"

 

decorated函数的所有参数会被传至__call__()。输出结果是:

 

Inside __init__()

After decoration

Preparing to call sayHello()

Inside __call__()

sayHello arguments: say hello argument list

After self.f(*args)

After first sayHello() call

Inside __call__()

sayHello arguments: a different set of arguments

After self.f(*args)

After second sayHello() call

 

注意,__init__()是唯一一个被调用执行decoration的方法,每次调用decorated的sayHello()时就会调用__call__()。

 

含有参数的decorators

现在让我们来修改上面的代码,看看向decorator加入参数后结果是什么。

 

class decoratorWithArguments(object):

 

    def __init__(self, arg1, arg2, arg3):

        """

        If there are decorator arguments, the function

        to be decorated is not passed to the constructor!

        """

        print "Inside __init__()"

        self.arg1 = arg1

        self.arg2 = arg2

        self.arg3 = arg3

 

    def __call__(self, f):

        """

        If there are decorator arguments, __call__() is only called

        once, as part of the decoration process! You can only give

        it a single argument, which is the function object.

        """

        print "Inside __call__()"

        def wrapped_f(*args):

            print "Inside wrapped_f()"

            print "Decorator arguments:", self.arg1, self.arg2, self.arg3

            f(*args)

            print "After f(*args)"

        return wrapped_f

 

@decoratorWithArguments("hello", "world", 42)

def sayHello(a1, a2, a3, a4):

    print 'sayHello arguments:', a1, a2, a3, a4

 

print "After decoration"


print "Preparing to call sayHello()"

sayHello("say", "hello", "argument", "list")

print "after first sayHello() call"

sayHello("a", "different", "set of", "arguments")

print "after second sayHello() call"

 

从输出结果可以看到,加入参数使程序执行发生了很大变化。

 

Inside __init__()

Inside __call__()

After decoration

Preparing to call sayHello()

Inside wrapped_f()

Decorator arguments: hello world 42

sayHello arguments: say hello argument list

After f(*args)

after first sayHello() call

Inside wrapped_f()

Decorator arguments: hello world 42

sayHello arguments: a different set of arguments

After f(*args)

after second sayHello() call

 

现在decoration方法调用构造器,然后就马上调用__call__(),后者只能包含一个参数(函数对象)且返回替代原有函数的decorated函数对象。注意当前decoration期间__call__()仅被调用一次,此后从__call__()返回的decorated函数就可以在实际调用中使用了。

虽然这种机制有一定合理性—构造器在这里可获取decorator参数,但__call__()对象不能再作为decorated函数使用了。因此你必须使用__call__()执行decoration—可能第一次遇到这种与无参情况截然不同的方式你会比较吃惊,何况还必须编写和无参decorator完成不同的代码。

 

含decorator参数的decorator函数

最后,让我们看一个更复杂一点的decorator函数实现,它需要你处理所有细节:

 

def decoratorFunctionWithArguments(arg1, arg2, arg3):

    def wrap(f):

        print "Inside wrap()"

        def wrapped_f(*args):

            print "Inside wrapped_f()"

            print "Decorator arguments:", arg1, arg2, arg3

            f(*args)

            print "After f(*args)"

        return wrapped_f

    return wrap

 

@decoratorFunctionWithArguments("hello", "world", 42)

def sayHello(a1, a2, a3, a4):

    print 'sayHello arguments:', a1, a2, a3, a4

 

print "After decoration"

 

print "Preparing to call sayHello()"

sayHello("say", "hello", "argument", "list")

print "after first sayHello() call"

sayHello("a", "different", "set of", "arguments")

print "after second sayHello() call"

 

输出结果为:

 

Inside wrap()

After decoration

Preparing to call sayHello()

Inside wrapped_f()

Decorator arguments: hello world 42

sayHello arguments: say hello argument list

After f(*args)

after first sayHello() call

Inside wrapped_f()

Decorator arguments: hello world 42

sayHello arguments: a different set of arguments

After f(*args)

after second sayHello() call

 

decorator函数的返回值必须是一个封装待decorated函数的函数。也就是说,Python会保存返回函数然后在decoration期间调用,并传递待decorated函数。这也是为何有三层函数的原因:里面那个函数才是被替换的。

由于闭包,wrapped_f()有权访问decorator参数arg1, arg2 和arg3,而无需像在class版本中那样显式存储它们。然而,我也是在这里发现了“显胜于隐(explicit is better than implicit)”。即使该函数版本看起来要更加简洁紧凑,但我发现还是类版本容易理解,当然也就容易修改和维护。

 

下一节内容

在下一节中我会给出decorators的一些实例—基于Python开发的build system—然后在最后一节讨论类decorators。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值