国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Python - 裝飾器使用過程中的誤區

1fe1se / 994人閱讀

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

裝飾器基本概念

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

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

    @function_wrapper
    def function():
       pass

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

    def function():
        pass

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

函數包裝器 - 經典實現

    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
函數(function)自省

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

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

    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

然而,當我們想要獲取被包裝函數的參數(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在實現時,缺少functools.update_wrapper需要的某些屬性。這是functools.update_wrapper在 python2 中的 bug,3.2版本已被修復,參考 http://bugs.python.org/issue3445。

然而,在 python3 下執行,另一個問題出現了:

    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

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

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

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

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

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


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

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

轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/37523.html

相關文章

  • Python進階細節

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

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

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

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

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

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

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

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

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

    liuchengxu 評論0 收藏0

發表評論

0條評論

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