1. <s id="4jtld"></s>
    1. <span id="4jtld"><meter id="4jtld"></meter></span>

        <span id="4jtld"></span>
      1. <s id="4jtld"><noscript id="4jtld"><i id="4jtld"></i></noscript></s>
        溫馨提示×

        Python裝飾器的使用方法

        發布時間:2020-08-15 13:53:57 來源:億速云 閱讀:121 作者:小新 欄目:開發技術

        這篇文章將為大家詳細講解有關Python裝飾器的使用方法,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。

        介紹

        我寫這篇文章的主要目的是介紹裝飾器的高級用法。如果你對裝飾器知之甚少,或者對本文講到的知識點易混淆。我建議你復習下裝飾器基礎教程。
        本教程的目標是介紹裝飾器的一些有趣的用法。特別是怎樣在類中使用裝飾器,怎樣給裝飾器傳遞額外的參數。

        裝飾器 vs 裝飾器模式

        Decorator模式是一個面向對象的設計模式,它允許動態地往現有的對象添加行為。當你裝飾了一個對象,在某種程度上,你是在獨立于同一個類的其他實例的基礎上擴展其功能。
        Python裝飾器不是裝飾器模式的實現,它在函數、方法定義的時候添加功能,而不是在運行的時候添加。Decorator設計模式本身可以在Python中實現,因為Python是動態編程語言,所以沒有必要這樣做。

        一個基礎的裝飾器

        這是裝飾器的最簡單例子,在繼續往下面閱讀之前請確保理解此段代碼。如果你需要更多關于此代碼的解釋,請復習下基礎裝飾器教程。

        def time_this(original_function): 
          def new_function(*args, **kwargs):
            import datetime 
            before = datetime.datetime.now() 
            x = original_function(*args, **kwargs) 
            after = datetime.datetime.now() 
            print("Elapsed Time = {}".format(after-before)) 
            return x 
          return new_function
        @time_this
        def func_a(stuff): 
          import time 
          time.sleep(stuff) 
          func_a(3)
        # out:
        Elapsed Time = 0:00:03.012472

        帶參數的裝飾器

        有時候帶參數的裝飾器會非常有用,這種技術經常用在函數注冊中。在web框架Pyramid中經常有用到,例如:

        @view_config(route_name='home', renderer='templates/mytemplate.pt')
        def my_view(request): 
          return {'project': 'hello decorators'} 

        比方說,我們有一個用戶可以登錄并且可以和用戶交互的GUI應用程序。用戶和GUI界面的交互觸發事件,導致Python函數執行。假設有許多使用該圖形界面的用戶,他們各自的權限級別差異很大,不同的功能執行需要不同的權限。比如,考慮以下功能:

        # 假設這些函數是存在的
        def current_user_id(): 
          """ this function returns the current logged in user id, if the use is not authenticated the return None """
        def get_permissions(iUserId): 
          """ returns a list of permission strings for the given user. For example ['logged_in','administrator','premium_member'] """
        # 在這些函數中我們需要實現權限檢查 
        def delete_user(iUserId): 
          """ delete the user with the given Id. This function is only accessable to users with administrator permissions """ 
        def new_game(): 
          """ any logged in user can start a new game """ 
        def premium_checkpoint(): 
          """ save the game progress, only accessable to premium members """

        一種實現這些權限檢查的方式是實現多個裝飾器,比如:

        def requires_admin(fn): 
          def ret_fn(*args,**kwargs): 
            lPermissions = get_permissions(current_user_id()) 
            if 'administrator' in lPermissions: 
              return fn(*args,**kwargs) 
            else: raise Exception("Not allowed") 
          return ret_fn
        def requires_logged_in(fn): 
          def ret_fn(*args,**kwargs): 
            lPermissions = get_permissions(current_user_id()) 
            if 'logged_in' in lPermissions: 
              return fn(*args,**kwargs) 
            else: 
              raise Exception("Not allowed") 
            return ret_fn 
        def requires_premium_member(fn): 
          def ret_fn(*args,**kwargs): 
            lPermissions = get_permissions(current_user_id()) 
            if 'premium_member' in lPermissions: 
              return fn(*args,**kwargs) 
            else: 
              raise Exception("Not allowed") 
            return ret_fn 
        @requires_admin
        def delete_user(iUserId): 
        """ delete the user with the given Id. This function is only accessable to users with administrator permissions """
        @requires_logged_in
        def new_game(): 
        """ any logged in user can start a new game """ @requires_premium_member
        def premium_checkpoint(): 
        """ save the game progress, only accessable to premium members """

        但是,這太可怕了。這需要大量的復制粘貼,每個裝飾器需要一個不同的名字,如果有任何關于權限檢查的改變,每個裝飾器都需要修改。就沒有一個裝飾器把以上三個裝飾器的工作都干了的嗎?

        為了解決此問題,我們需要一個返回裝飾器的函數:

        def requires_permission(sPermission): 
          def decorator(fn): 
            def decorated(*args,**kwargs): 
              lPermissions = get_permissions(current_user_id()) 
              if sPermission in lPermissions: 
                return fn(*args,**kwargs)
              raise Exception("permission denied") 
            return decorated 
          return decorator
        def get_permissions(iUserId): 
          # this is here so that the decorator doesn't throw NameErrors 
          return ['logged_in',]
        def current_user_id(): 
          #ditto on the NameErrors 
          return 1
        #and now we can decorate stuff... 
        @requires_permission('administrator')
        def delete_user(iUserId): 
        """ delete the user with the given Id. This function is only accessible to users with administrator permissions """
        @requires_permission('logged_in')
        def new_game(): 
        """ any logged in user can start a new game """ @requires_permission('premium_member')
        def premium_checkpoint(): 
        """ save the game progress, only accessable to premium members """

        嘗試一下調用delete_user,new namepremium_checkpoint然后看看發生了什么。
        premium_checkpointdelete_user 產生了一個“permission denied”的異常,new_game執行正常。
        下面是帶參數裝飾的一般形式,和例子的使用:

        def outer_decorator(*outer_args,**outer_kwargs): 
          def decorator(fn): 
            def decorated(*args,**kwargs):
              do_something(*outer_args,**outer_kwargs) 
              return fn(*args,**kwargs) 
            return decorated 
          return decorator 
        @outer_decorator(1,2,3)
        def foo(a,b,c): 
          print(a) 
          print(b) 
          print(c)
        foo()

        等價于:

        def decorator(fn): 
          def decorated(*args,**kwargs): 
            do_something(1,2,3) 
            return fn(*args,**kwargs) 
          return decorated 
        return decorator 
        @decorator
        def foo(a,b,c): 
          print(a)
          print(b) 
          print(c)
        foo()

        類裝飾器

        裝飾器不僅可以修飾函數,還可以對類進行裝飾。比如說,我們有一個類,該類含有許多重要的方法,我們需要記錄每一個方法執行的時間。我們可以使用上述的time_this裝飾此類:

        class ImportantStuff(object): 
        @time_this 
        def do_stuff_1(self): 
          pass
        @time_this 
        def do_stuff_2(self): 
          pass
        @time_this 
        def do_stuff_3(self): 
          pass

        此方法可以運行正常。但是在該類中存在許多多余的代碼,如果我們想建立更多的類方法并且遺忘了裝飾其中的一個方法,如果我們不想裝飾該類中的方法了,會發生什么樣的情況呢?這可能會存在出現認為錯誤的空間,如果寫成這樣會更有好:

        @time_all_class_methods
        class ImportantStuff: 
          def do_stuff_1(self):
            pass
          def do_stuff_2(self):
            pass
          def do_stuff_3(self):
            pass

        等價于:

        class ImportantStuff: 
          def do_stuff_1(self):
            pass
          def do_stuff_2(self):
            pass
          def do_stuff_3(self):
            pass
        ImportantStuff = time_all_class_methods(ImportantStuff)

        那么time_all_class_methods是怎么工作的呢?
        首先,我們需要采用一個類作為參數,然后返回一個類,我們也要知道返回的類的功能應該和原始類ImportantStuff功能一樣。也就是說,我們仍然希望做重要的事情,我們希望記錄下每個步驟發生的時間。我們寫成這樣:

        def time_this(original_function): 
          print("decorating") 
          def new_function(*args,**kwargs): 
            print("starting timer") 
            import datetime 
            before = datetime.datetime.now() 
            x = original_function(*args,**kwargs) 
            after = datetime.datetime.now() 
            print("Elapsed Time = {0}".format(after-before)) 
            return x 
          return new_function
        def time_all_class_methods(Cls): 
          class NewCls: 
            def __init__(self,*args,**kwargs): 
              self.oInstance = Cls(*args,**kwargs) 
            def __getattribute__(self,s): 
              try: 
                x = super(NewCls,self).__getattribute__(s) 
              except AttributeError: 
                pass 
              else: 
                return x 
              x = self.oInstance.__getattribute__(s) 
              if type(x) == type(self.__init__): 
                return time_this(x) 
              else: 
                return x 
            return NewCls
        @time_all_class_methods
        class Foo: 
          def a(self): 
            print("entering a") 
            import time 
            time.sleep(3) 
            print("exiting a")
        oF = Foo()
        oF.a()
        # out:
        decorating
        starting timer
        entering a
        exiting a
        Elapsed Time = 0:00:03.006767

        總結

        在此篇教程中,我們給大家展示了一些Python裝飾器使用的技巧-我們介紹了怎么樣把參數傳遞給裝飾器,怎樣裝飾類。但是這僅僅是冰山一角。除了本文介紹的之外,還有其他好多裝飾器的使用方法,我們甚至可以使用裝飾器裝飾裝飾器(如果你有機會使用到它,這可能是一個做全面檢查的好方法)。Python有一些內置的裝飾器,比如:staticmethod,classmethod

        關于Python裝飾器的使用方法就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。

        免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

        主題地圖

        欧美午夜理伦三级在线观看,欧美午夜乱伦片,欧美午夜乱色视频在线观看,欧美午夜免费一区二区,欧美午夜片欧美片在线观看