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

資訊專欄INFORMATION COLUMN

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

1fe1se / 991人閱讀

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

裝飾器基本概念

大家都知道裝飾器是一個很著名的設(shè)計模式,經(jīng)常被用于 AOP (面向切面編程)的場景,較為經(jīng)典的有插入日志,性能測試,事務(wù)處理,Web權(quán)限校驗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ù)包裝器 - 經(jīng)典實現(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)自省

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

針對某個函數(shù)應(yīng)用裝飾器時,這個函數(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 標(biāo)準(zhǔn)庫提供了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

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

    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)

當(dāng)包裝器(@function_wrapper)被應(yīng)用于@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版本已被修復(fù),參考 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

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

總結(jié) - 簡單并不意味著正確

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

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

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


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

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

轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/37523.html

相關(guān)文章

  • Python進(jìn)階細(xì)節(jié)

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

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

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

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

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

    justCoding 評論0 收藏0
  • Python裝飾學(xué)習(xí)筆記

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

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

    摘要:裝飾器的使用符合了面向?qū)ο缶幊痰拈_放封閉原則。三簡單的裝飾器基于上面的函數(shù)執(zhí)行時間的需求,我們就手寫一個簡單的裝飾器進(jìn)行實現(xiàn)。函數(shù)體就是要實現(xiàn)裝飾器的內(nèi)容。類裝飾器的實現(xiàn)是調(diào)用了類里面的函數(shù)。類裝飾器的寫法比我們裝飾器函數(shù)的寫法更加簡單。 目錄 前言 一、什么是裝飾器 二、為什么要用裝飾器 ...

    liuchengxu 評論0 收藏0

發(fā)表評論

0條評論

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