成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Python - 裝飾器使用過程中的誤區(qū)

1fe1se / 996人閱讀

摘要:然而,當我們想要獲取被包裝函數(shù)的參數(shù)或源代碼時,同樣不能得到我們想要的結果。這是在中的,版本已被修復,參考。如同上面我們所看到的,可以幫我們解決和的問題,但對于獲取函數(shù)的參數(shù)或源代碼則束手無策。

裝飾器基本概念

大家都知道裝飾器是一個很著名的設計模式,經常被用于 AOP (面向切面編程)的場景,較為經典的有插入日志,性能測試,事務處理,Web權限校驗, Cache等。

Python 語言本身提供了裝飾器語法(@),典型的裝飾器實現(xiàn)如下:

    @function_wrapper
    def function():
       pass

@實際上是 python2.4 才提出的語法糖,針對 python2.4 以前的版本有另一種等價的實現(xiàn):

    def function():
        pass

    function = function_wrapper(function)
裝飾器的兩種實現(xiàn)

函數(shù)包裝器 - 經典實現(xiàn)

    def function_wrapper(wrapped):
        def _wrapper(*args, **kwargs):
            return wrapped(*args, **kwargs)
        return _wrapper 

    @function_wrapper
    def function():
        pass

類包裝器 - 易于理解

    class function_wrapper(object):
        def __init__(self, wrapped):
            self.wrapped = wrapped
        def __call__(self, *args, **kwargs):
            return self.wrapped(*args, **kwargs)

    @function_wrapper
    def function():
        pass
函數(shù)(function)自省

當我們談到一個函數(shù)時,通常希望這個函數(shù)的屬性像其文檔上描述的那樣,是被明確定義的,例如__name____doc__

針對某個函數(shù)應用裝飾器時,這個函數(shù)的屬性就會發(fā)生變化,但這并不是我們所期望的。

    def function_wrapper(wrapped):
        def _wrapper(*args, **kwargs):
            return wrapped(*args, **kwargs)
        return _wrapper 

    @function_wrapper
    def function():
        pass 

    >>> print(function.__name__)
    _wrapper

python 標準庫提供了functools.wraps(),來解決這個問題。

    import functools 

    def function_wrapper(wrapped):
        @functools.wraps(wrapped)
        def _wrapper(*args, **kwargs):
            return wrapped(*args, **kwargs)
        return _wrapper 

    @function_wrapper
    def function():
        pass 

    >>> print(function.__name__)
    function

然而,當我們想要獲取被包裝函數(shù)的參數(shù)(argument)或源代碼(source code)時,同樣不能得到我們想要的結果。

    import inspect 

    def function_wrapper(wrapped): ...

    @function_wrapper
    def function(arg1, arg2): pass 

    >>> print(inspect.getargspec(function))
    ArgSpec(args=[], varargs="args", keywords="kwargs", defaults=None)

    >>> print(inspect.getsource(function))
        @functools.wraps(wrapped)
        def _wrapper(*args, **kwargs):
            return wrapped(*args, **kwargs)
包裝類方法(@classmethod)

當包裝器(@function_wrapper)被應用于@classmethod時,將會拋出如下異常:

    class Class(object):
        @function_wrapper
        @classmethod
        def cmethod(cls):
            pass 

    Traceback (most recent call last):
      File "", line 1, in 
      File "", line 3, in Class
      File "", line 2, in wrapper
      File ".../functools.py", line 33, in update_wrapper
        setattr(wrapper, attr, getattr(wrapped, attr))
    AttributeError: "classmethod" object has no attribute "__module__"

因為@classmethod在實現(xiàn)時,缺少functools.update_wrapper需要的某些屬性。這是functools.update_wrapper在 python2 中的 bug,3.2版本已被修復,參考 http://bugs.python.org/issue3445。

然而,在 python3 下執(zhí)行,另一個問題出現(xiàn)了:

    class Class(object):
        @function_wrapper
        @classmethod
        def cmethod(cls):
            pass 

    >>> Class.cmethod() 
    Traceback (most recent call last):
      File "classmethod.py", line 15, in 
        Class.cmethod()
      File "classmethod.py", line 6, in _wrapper
        return wrapped(*args, **kwargs)
    TypeError: "classmethod" object is not callable

這是因為包裝器認定被包裝的函數(shù)(@classmethod )是可以直接被調用的,但事實并不一定是這樣的。被包裝的函數(shù)實際上可能是描述符(descriptor ),意味著為了使其可調用,該函數(shù)(描述符)必須被正確地綁定到某個實例上。關于描述符的定義,可以參考 https://docs.python.org/2/howto/descriptor.html。

總結 - 簡單并不意味著正確

盡管大家實現(xiàn)裝飾器所用的方法通常都很簡單,但這并不意味著它們一定是正確的并且始終能正常工作。

如同上面我們所看到的,functools.wraps() 可以幫我們解決__name____doc__ 的問題,但對于獲取函數(shù)的參數(shù)(argument)或源代碼( source code )則束手無策。

以上問題,wrapt 都可以幫忙解決,詳細用法可參考其官方文檔:http://wrapt.readthedocs.org


本文作者系OneAPM 工程師曾靈敏 ,想閱讀更多好的技術文章,請訪問 OneAPM 官方技術博客。

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉載請注明本文地址:http://systransis.cn/yun/37523.html

相關文章

  • Python進階細節(jié)

    摘要:進階細節(jié)根據(jù)慕課網七月老師視頻整理一切皆對象對與來說,一切皆對象,包括函數(shù)。閉包的意義在于返回了一個現(xiàn)場,如果沒有閉包,很容易被外部的變量所影響。重復定義可見此時返回了不再是閉包了。注意該方法的返回值只能是布爾類型,即或。 Python進階細節(jié) 根據(jù)慕課網七月老師視頻整理 一切皆對象 對與Python來說,一切皆對象,包括函數(shù)。在其他語言比如c++中,函數(shù)只是一段可執(zhí)行的代碼,只要你獲...

    tomato 評論0 收藏0
  • Python中的函數(shù)裝飾和閉包

    摘要:變量查找規(guī)則在中一個變量的查找順序是局部環(huán)境,閉包,全局,內建閉包引用了自由變量的函數(shù)。閉包的作用閉包的最大特點是可以將父函數(shù)的變量與內部函數(shù)綁定,并返回綁定變量后的函數(shù),此時即便生成閉包的環(huán)境父函數(shù)已經釋放,閉包仍然存在。 導語:本文章記錄了本人在學習Python基礎之函數(shù)篇的重點知識及個人心得,打算入門Python的朋友們可以來一起學習并交流。 本文重點: 1、掌握裝飾器的本質、功...

    caozhijian 評論0 收藏0
  • Python 的閉包和裝飾

    摘要:所以,有另一種說法認為閉包是由函數(shù)和與其相關的引用環(huán)境組合而成的實體。 對于已經對 閉包 或者 裝飾器有一定概念的,可以直接通過右側標題目錄直接定位到相應段落查看所需的內容。 什么是裝飾器? 裝飾器(Decorator)相對簡單,咱們先介紹它:裝飾器的功能是將被裝飾的函數(shù)當作參數(shù)傳遞給與裝飾器對應的函數(shù)(名稱相同的函數(shù)),并返回包裝后的被裝飾的函數(shù),聽起來有點繞,沒關系,直接看示意圖,...

    justCoding 評論0 收藏0
  • Python裝飾學習筆記

    摘要:前言最近跟著流暢的和學習,看到裝飾器部分,有些頭大倒不是因為概念難以理解,而是書和網上文章中有些地方有些矛盾之處在簡單學習和實踐之后,整理出我對裝飾器的理解如下裝飾器的定義在不同語境下,裝飾器有不一樣的含義,我大致認為有種定義一種把另一個對 前言 最近跟著《流暢的Python》和《Python Cookbook》學習,看到裝飾器部分,有些頭大倒不是因為概念難以理解,而是書和網上文章中有...

    Cristalven 評論0 收藏0
  • Python】一文弄懂python裝飾(附源碼例子)

    摘要:裝飾器的使用符合了面向對象編程的開放封閉原則。三簡單的裝飾器基于上面的函數(shù)執(zhí)行時間的需求,我們就手寫一個簡單的裝飾器進行實現(xiàn)。函數(shù)體就是要實現(xiàn)裝飾器的內容。類裝飾器的實現(xiàn)是調用了類里面的函數(shù)。類裝飾器的寫法比我們裝飾器函數(shù)的寫法更加簡單。 目錄 前言 一、什么是裝飾器 二、為什么要用裝飾器 ...

    liuchengxu 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<