Python自定義注解


Python3.0之后加入新特性Decorators,以@為標記修飾function和class。有點類似c++的宏和java的注解。Decorators用以修飾約束function和class,分為帶參數和不帶參數,影響原有輸出,例如類靜態函數我們要表達的時候需要函數前面加上修飾@staticmethod或@classmethod,為什么這樣做呢?下面用簡單的例子來看一下,具體內容可以查看:官方解釋

不帶參數的單一使用

def spamrun(fn): def sayspam(*args): print("spam,spam,spam") fn(*args) return sayspam @spamrun def useful(a,b): print(a*b) if __name__ == "__main__" useful(2,5) 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

運行結果

spam,spam,spam
10
  • 1
  • 2

函數useful本身應該只是打印10,可是為什么最后的結果是這樣的呢,其實我們可以簡單的把這個代碼理解為

def spamrun(fn): def sayspam(*args): print("spam,spam,spam") fn(*args) return sayspam def useful(a,b): print(a*b) if __name__ == "__main__" useful = spamrun(useful) useful(a,b)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

不帶參數的多次使用

def spamrun(fn): def sayspam(*args): print("spam,spam,spam") fn(*args) return sayspam def spamrun1(fn): def sayspam1(*args): print("spam1,spam1,spam1") fn(*args) return sayspam1 @spamrun @spamrun1 def useful(a,b): print(a*b) if __name__ == "__main__" useful(2,5) 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

運行結果

spam,spam,spam
spam1,spam1,spam1
10
  • 1
  • 2
  • 3

這個代碼理解為

if __name__ == "__main__" useful = spamrun1(spamrun(useful)) useful(a,b)
  • 1
  • 2
  • 3

帶參數的單次使用

def attrs(**kwds): def decorate(f): for k in kwds: setattr(f, k, kwds[k]) return f return decorate @attrs(versionadded="2.2", author="Guido van Rossum") def mymethod(f): print(getattr(mymethod,'versionadded',0)) print(getattr(mymethod,'author',0)) print(f) if __name__ == "__main__" mymethod(2) 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

運行結果

2.2
Guido van Rossum
2
  • 1
  • 2
  • 3

這個代碼理解為

if __name__ == "__main__" mymethod = attrs(versionadded="2.2", author="Guido van Rossum).(mymethod) mymethod(2)
  • 1
  • 2
  • 3
  • 4

帶參數的多次使用 
這次我們來看一個比較實際的例子,檢查我們函數的輸入輸出是否符合我們的標准,比如我們希望的輸入是(int,(int,float))輸出是(int,float),這個例子在官網里有,但是在3.6版本中使用有些問題,這里進行了一些改動,如果要進一步了解可以看下functionTool。

def accepts(*types): def check_accepts(f): def new_f(*args, **kwds): assert len(types) == (len(args) + len(kwds)), \ "args cnt %d does not match %d" % (len(args) + len(kwds), len(types)) for (a, t) in zip(args, types): assert isinstance(a, t), \ "arg %r does not match %s" % (a, t) return f(*args, **kwds) update_wrapper(new_f, f) return new_f return check_accepts def returns(rtype): def check_returns(f): def new_f(*args, **kwds): result = f(*args, **kwds) assert isinstance(result, rtype), \ "return value %r does not match %s" % (result, rtype) return result update_wrapper(new_f, f) return new_f return check_returns @accepts(int, (int, float)) @returns((int, float)) def func(arg1, arg2): return arg1 * arg2 if __name__ == "__main__" a = func(1, 'b') print(a) 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38

這里故意輸入了錯誤的參數,所以運行結果將我們的斷言打印了出來

AssertionError: arg 'b' does not match (<class 'int'>, <class 'float'>)
  • 1

這個代碼理解為

if __name__ == "__main__" func = accepts(int, (int, float)).(accepts((int, float)).(mymethod)) a = func(1, 'b') print(a)
  • 1
  • 2
  • 3
  • 4

說到這里,大家不難看出其實我們可以使用Decorators做很多工作,簡化代碼,使邏輯更清晰等。還有更多的用法等着大家自己去挖掘了,這里只簡單的介紹了針對函數的用法,其實還可以針對class使用,具體的大家自己看看官方介紹,結合這篇文檔應該就不難理解了。

 

引自:https://blog.csdn.net/u013474436/article/details/75675113


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM