摘要:如果對象定義和,則它被認為是數據描述符。屬性查找優先級為類屬性數據描述符實例屬性非數據描述符默認為內部是用實現的,這里用模擬實現功能代碼參考官方文檔原理代碼實現原理代碼實現原理參考資料,知乎如何理解裝飾器,
概要
本人python理論知識遠達不到傳授級別,寫文章主要目的是自我總結,并不能照顧所有人,請見諒,文章結尾貼有相關鏈接可以作為補充
全文分為三個部分裝飾器理論知識、裝飾器應用、裝飾器延申
裝飾理基礎:無參裝飾器、有參裝飾器、functiontools、裝飾器鏈
裝飾器進階:property、staticmethod、classmethod源碼分析(python代碼實現)
""" 假定有一個需求是:打印程序函數運行順序 此案例打印的結果為: foo1 function is starting foo2 function is starting """ from functools import wraps def NoParamDec(func): #函數在被裝飾器裝時后,其函數屬性也會改變,wraps作用就是保證被裝飾函數屬性不變 @wraps(func) def warpper(*args, **kwargs): print("{} function is starting".format(func.__name__)) return func(*args, **kwargs) return warpper #python黑魔法省略了NoParamDec=NoParamDec(foo1) @NoParamDec def foo1(): foo2() @NoParamDec def foo2(): pass if __name__ == "__main__": foo1()有參裝飾器
""" 假定有一個需求是:檢查函數參數的類型,只允許匹配正確的函數通過程序 此案例打印結果為: ("a", "b", "c") -----------------------分割線------------------------ ERROS!!!!b must be裝飾器鏈ERROS!!!!c must be ("a", 2, ["b", "d"]) """ from functools import wraps from inspect import signature def typeAssert(*args, **kwargs): deco_args = args deco_kwargs = kwargs def factor(func): #python標準模塊類,可以用來檢查函數參數類型,只允許特定類型通過 sig = signature(func) #將函數形式參數和規定類型進行綁定 check_bind_args = sig.bind_partial(*deco_args, **deco_kwargs).arguments @wraps(func) def wrapper(*args, **kwargs): #將實際參數值和形式參數進行綁定 wrapper_bind_args = sig.bind(*args, **kwargs).arguments.items() for name, obj in wrapper_bind_args: #遍歷判斷是否實際參數值是規定參數的實例 if not isinstance(obj, check_bind_args[name]): try: raise TypeError("ERROS!!!!{arg} must be {obj} ".format(**{"arg": name, "obj": check_bind_args[name]})) except Exception as e: print(e) return func(*args, **kwargs) return wrapper return factor @typeAssert(str, str, str) def inspect_type(a, b, c): return (a, b, c) if __name__ == "__main__": print(inspect_type("a", "b", "c")) print("{:-^50}".format("分割線")) print(inspect_type("a", 2, ["b", "d"]))
""" 假定有一個需求是: 輸入類似代碼: @makebold @makeitalic def say(): return "Hello" 輸出: Hello """ from functools import wraps def html_deco(tag): def decorator(fn): @wraps(fn) def wrapped(*args, **kwargs): return "<{tag}>{fn_result}<{tag}>".format(**{"tag": tag, "fn_result": fn(*args, **kwargs)}) return wrapped return decorator @html_deco("b") @html_deco("i") def greet(whom=""): # 等價于 geet=html_deco("b")(html_deco("i)(geet)) return "Hello" + (" " + whom) if whom else "" if __name__ == "__main__": print(greet("world")) # -> Hello world裝飾器進階 property 原理
通常,描述符是具有“綁定行為”的對象屬性,其屬性訪問已經被描述符協議中的方法覆蓋。這些方法是__get__()、__set__()和__delete__()。如果一個對象定義這些方法中的任何一個,它被稱為一個描述符。如果對象定義__get__()和__set__(),則它被認為是數據描述符。僅定義__get__()的描述器稱為非數據描述符(它們通常用于方法,但是其他用途也是可能的)。
屬性查找優先級為:
類屬性
數據描述符
實例屬性
非數據描述符
默認為__getattr__()
class Property(object): """ 內部property是用c實現的,這里用python模擬實現property功能 代碼參考官方doc文檔 """ def __init__(self, fget=None, fset=None, fdel=None, doc=None): self.fget = fget self.fset = fset self.fdel = fdel self.__doc__ = doc def __get__(self, obj, objtype=None): if obj is None: return self if self.fget is None: raise (AttributeError, "unreadable attribute") print("self={},obj={},objtype={}".format(self,obj,objtype)) return self.fget(obj) def __set__(self, obj, value): if self.fset is None: raise (AttributeError, "can"t set attribute") self.fset(obj, value) def __delete__(self, obj): if self.fdel is None: raise (AttributeError, "can"t delete attribute") self.fdel(obj) def getter(self, fget): return type(self)(fget, self.fset, self.fdel, self.__doc__) def setter(self, fset): return type(self)(self.fget, fset, self.fdel, self.__doc__) def deleter(self, fdel): return type(self)(self.fget, self.fset, fdel, self.__doc__) class Student( object ): @Property def score( self ): return self._score @score.setter def score( self, val ): if not isinstance( val, int ): raise ValueError( "score must be an integer!" ) if val > 100 or val < 0: raise ValueError( "score must between 0 ~ 100!" ) self._score = val if __name__ == "__main__": s = Student() s.score = 60 s.scorestaticmethod 原理
@staticmethod means: when this method is called, we don"t pass an instance of the class to it (as we normally do with methods). This means you can put a function inside a class but you can"t access the instance of that class (this is useful when your method does not use the instance).
class StaticMethod(object): "python代碼實現staticmethod原理" def __init__(self, f): self.f = f def __get__(self, obj, objtype=None): return self.f class E(object): #StaticMethod=StaticMethod(f) @StaticMethod def f( x): return x if __name__ == "__main__": print(E.f("staticMethod Test"))classmethod
@staticmethod means: when this method is called, we don"t pass an instance of the class to it (as we normally do with methods). This means you can put a function inside a class but you can"t access the instance of that class (this is useful when your method does not use the instance).
class ClassMethod(object): "python代碼實現classmethod原理" def __init__(self, f): self.f = f def __get__(self, obj, klass=None): if klass is None: klass = type(obj) def newfunc(*args): return self.f(klass, *args) return newfunc class E(object): #ClassMethod=ClassMethod(f) @ClassMethod def f(cls,x): return x if __name__ == "__main__": print(E().f("classMethod Test"))參考資料
1, statckoverflow: how to make a chain of decorators
2, python doc:how to descriptor
3,知乎:如何理解裝飾器
4, difference-between-staticmethod-and-classmethod-in-python
5,meaning-of-classmethod-and-staticmethod-for-beginner
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/41438.html
摘要:最近在閱讀微型框架的源碼,發現了中有一個既是裝飾器類又是描述符的有趣實現。所以第三版的代碼可以這樣寫第三版的代碼沒有使用裝飾器,而是使用了描述符這個技巧。更大的問題來自如何將描述符與裝飾器結合起來,因為是一個類而不是方法。 最近在閱讀Python微型Web框架Bottle的源碼,發現了Bottle中有一個既是裝飾器類又是描述符的有趣實現。剛好這兩個點是Python比較的難理解,又混合在...
摘要:所以這是一篇插隊的文章,用于去理解中的裝飾器和概念。因此,該的作用就是根據入參返回具體的描述符。其次局部來看,裝飾器具體應用表達式是,其函數簽名和是一模一樣。等裝飾器語法,是和直接使用是等效等價的。 ================前言=================== 初衷:以系列故事的方式展現 MobX 源碼邏輯,盡可能以易懂的方式講解源碼; 本系列文章: 《【用故事解...
摘要:的裝飾器中的同樣借鑒了這個語法糖,不過依賴于的方法。等同于也就是說,裝飾器是一個對類進行處理的函數。別名或裝飾器在控制臺顯示一條警告,表示該方法將廢除。有了裝飾器,就可以改寫上面的代碼。 更多文章,請在Github blog查看 在 ES6 中增加了對類對象的相關定義和操作(比如 class 和 extends ),這就使得我們在多個不同類之間共享或者擴展一些方法或者行為的時候,變得并...
摘要:然而,當我們想要獲取被包裝函數的參數或源代碼時,同樣不能得到我們想要的結果。這是在中的,版本已被修復,參考。如同上面我們所看到的,可以幫我們解決和的問題,但對于獲取函數的參數或源代碼則束手無策。 裝飾器基本概念 大家都知道裝飾器是一個很著名的設計模式,經常被用于 AOP (面向切面編程)的場景,較為經典的有插入日志,性能測試,事務處理,Web權限校驗, Cache等。 Python...
摘要:具體怎么實現的呢,思想其實特別簡單,我們在深入理解中的變量上一文的最后有提起過,就是創建一個全局字典,然后將線程或者協程標識符作為,相應線程或協程的局部數據作為。 在上篇我們看到了 ThreadLocal 變量的簡單使用,中篇對python中 ThreadLocal 的實現進行了分析,但故事還沒有結束。本篇我們一起來看下Werkzeug中ThreadLocal的設計。 Werkzeug...
閱讀 2849·2021-08-20 09:37
閱讀 1607·2019-08-30 12:47
閱讀 1090·2019-08-29 13:27
閱讀 1685·2019-08-28 18:02
閱讀 749·2019-08-23 18:15
閱讀 3084·2019-08-23 16:51
閱讀 931·2019-08-23 14:13
閱讀 2125·2019-08-23 13:05