Python Decorators(二):Decorator參數__Python

來源:互聯網
上載者:User

Python Decorators II: Decorator Arguments

October 19, 2008

 

(本文是Python 3 Patterns & Idioms(Python3之模式和用法)一書的章節節選第二部分,點擊這裡閱讀第一部分)

 

回顧:不含參數的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):

相關文章
阿里云产品大规模降价
  • 最高幅度達59%,平均降幅23%
  • 核心產品降價
  • 多地區降價
undefined. /
透過 Discord 與我們聯繫
  • 安全、匿名的群聊,不受干擾
  • 隨時了解活動、活動、新產品等訊息
  • 支持您的所有問題
undefined. /
免費試用
  • 開啟從ECS到大數據的免費試用之旅
  • 只需三步 輕鬆上雲
  • 免費試用ECS t5 1C1G
undefined. /

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.