日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > python >内容正文

python

python的__get__、__set__、__delete__(1)

發布時間:2025/5/22 python 17 豆豆
生活随笔 收集整理的這篇文章主要介紹了 python的__get__、__set__、__delete__(1) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

內容:
??? 描述符引導
??????? 摘要
??????? 定義和介紹
??????? 描述符協議
??????? 調用描述符
??????? 樣例
??????? Properties
??????? 函數和方法
??????? 靜態方法和類方法
?????? ?
?? ?
摘要
??? 定義并展示如何調用描述符,展示自定義描述符和幾個內置的python描述符,包括函數、屬性、靜態方法和類方法,通過給出一個Python的示例應用來展示描述符是如何工作的.
??? 熟練掌握描述符不僅讓你擁有python使用的額外技巧,并且可以加深對Python內部如何工作的理解,提升對程序設計的能力,而且體會到python的設計優雅之處

定義和介紹
??? 一般來說,描述符是帶有“綁定行為”的對象屬性,它的屬性訪問已經被描述符協議中的方法覆蓋了.這些方法是__get__(),__set__(),和__delete__().
??? 如果一個對象定義了這些方法中的任何一個,它就是一個描述符.

??? 默認的屬相訪問是從對象的字典中 get, set, 或者 delete 屬性,;例如a.x的查找順序是:
??? a.x -> a.__dict__['x'] -> type(a).__dict__['x'] -> type(a)的基類(不包括元類),如果查找的值是對象定義的描述方法之一,python可能會調用描述符方法來重載默認行為,
??? 發生在這個查找環節的哪里取決于定義了哪些描述符方法
??? 注意,只有在新式類中描述符才會起作用(新式類繼承type或者object class)
??? 描述符是強有力的通用協議,屬性、方法、靜態方法、類方法和super()背后使用的就是這個機制,描述符簡化了底層的c代碼,并為Python編程提供了一組靈活的新工具


描述符協議

descr.__get__(self, obj, type=None) -> valuedescr.__set__(self, obj, value) -> Nonedescr.__delete__(self, obj) -> None


??? 定義任何上面三個方法的任意一個,這個對象就會被認為是一個描述符,并且可以在被作為對象屬性時重載默認的行為, 如果一個對象定義了__get__() 和 __set__(),它被認為是一個數據描述符.只定義 __get__()被認為是非數據描述符,數據和非數據描述符的區別在于:如果一個實例的字典有和數據描述符同名的屬性,那么數據描述符會被優先使用,如果一個實例的字典實現了無數據描述符的定義,那么這個字典中的屬性會被優先使用,實現只讀數據描述符,同時定義__get__()和__set__(),在__set__()中拋出AttributeError.

描述符調用

??? 描述符可以直接用方法名稱調用,比如:d.__get__(obj)
?? ?
??? 然而,描述符更常用的方式是屬性訪問時被自動調用,例如:obj.d 在obj的字典中查找d,如果d定義了方法__get__(),然后d.__get__(obj)會被通過下面的優先級列表調用
??? 詳細的調用依賴于obj是一個對象還是一個類,不管哪種方式,描述符只工作在新式對象和類,如果一個類是object的子類(繼承object),這個類就是一個新式類
?? ?
??? 對于對象來說,object.__getattribute__() 把b.x 變為 type(b).__dict__['x'].__get__(b, type(b)) .優先級順序:
??? 數據描述符 > 實例變量 > 非數據描述符,__getattr__()具有最低優先級(如果實現了的話),C語言的實現可以在 Objects/object.c 中 PyObject_GenericGetAttr() 查看.
?? ?
??? 對于類來說,type.__getattribute__() 把 B.x 變為 B.__dict__['x'].__get__(None, B),代碼實現為:
?? ?

def __getattribute__(self, key):"Emulate type_getattro() in Objects/typeobject.c"v = object.__getattribute__(self, key)if hasattr(v, '__get__'):return v.__get__(None, self)return v


??? 重點:
??????? 描述符被__getattribute()方法調用
??????? 重載__getattribute__()會阻止描述符自動調用
??????? __getattribute__()只適用于新式類和對象
??????? object.__getattribute__()和type.__getattribute__()對__get__()的調用不一樣
??????? 數據描述符會重載實例字典
??????? 非數據描述符可能會被實例字典重載
?????? ?
???? super()返回的對象會使用定制__getattribute__()方法來調用描述符,調用super(B, obj).m() 會在緊鄰著B的基類A搜索obj.__class__.__mro__然后返回A.__dict__['m'].__get__(obj, B),如果不是一個描述符,返回未改變的m
???? 如果不在字典中,m會調用 object.__getattribute__() 查詢

???? 注意:在python2.2,如果m是一個數據描述符,super(B, obj).m() 會調用__get__(),在python2.3,無數據描述符也會執行調用,除非是個舊式類,super_getattro() 的細節在Objects/typeobject.c中
??? ?
???? 上面展示的是描述符在object, type, and super() 的 __getattribute__() 方法中的實現機制,繼承object的類自動實現或者他們有一個元類提供類似的功能,同樣,重載 __getattribute__()可以停止描述符的調用
??? ?
描述符例子
??? 下面的代碼創建了一個類,每次訪問get或者set都會打印一條信息.重載__getattribute__()也可以使每個屬性實現這一方法,然而,描述符在查看特定的屬性時比較有用

class RevealAccess(object):"""A data descriptor that sets and returns valuesnormally and prints a message logging their access."""def __init__(self, initval=None, name='var'):self.val = initvalself.name = namedef __get__(self, obj, objtype):print 'Retrieving', self.namereturn self.valdef __set__(self, obj, val):print 'Updating', self.nameself.val = val>>> class MyClass(object):... x = RevealAccess(10, 'var "x"')... y = 5...>>> m = MyClass()>>> m.xRetrieving var "x"10>>> m.x = 20Updating var "x">>> m.xRetrieving var "x"20>>> m.y5

??? 這個協議很簡單卻又可以提供令人為之一振的可能性.Properties, bound 和 unbound methods, 靜態方法和 類方法 都是基于描述符協議

Properties
??? 調用property()是一種建立數據描述符的方便方法,可以在訪問一個屬性的時候觸發方法的調用
??? property(fget=None, fset=None, fdel=None, doc=None) -> property attribute

??? 下面展示一個定義管理屬性x的典型的樣例:

class C(object):def getx(self):return self.__xdef setx(self, value):self.__x = valuedef delx(self):del self.__xx = property(getx, setx, delx, "I'm the 'x' property.")

??? property()使用純python方式實現描述符:

class Property(object):"Emulate PyProperty_Type() in Objects/descrobject.c"def __init__(self, fget=None, fset=None, fdel=None, doc=None):self.fget = fgetself.fset = fsetself.fdel = fdelif doc is None and fget is not None:doc = fget.__doc__self.__doc__ = docdef __get__(self, obj, objtype=None):if obj is None:return selfif self.fget is None:raise AttributeError("unreadable attribute")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__)

?
??? 當用戶接口已經授權訪問屬性,這時候需求發生變化,property()可以提供便利, 例如,一個電子表格類可以通過單元('b10')授予對單元格值的訪問權.這時候,對程序的后續改進要求在每次訪問時重新計算單元格的值;然而,程序員不希望影響現有客戶端代碼.解決方案是在屬性數據描述符中封裝對value屬性的訪問:

class Cell(object):. . .def getvalue(self):"Recalculate the cell before returning value"self.recalc()return self._valuevalue = property(getvalue)


函數和方法
??? python的面向對象是建立在函數的基礎上,使用非數據描述符,兩者會結合的非常緊密.

??? 類的字典將方法比作函數存儲.在一個類的定義中,使用def和lambda來聲明方法,這是用于創建函數的常用工具. 唯一不同之處,就是第一個參數用來表示對象實例,python約定,實例引用可以使self或者this或者其他變量名稱

??? 為了支持方法調用,函數通過__get__()方法來實現屬性訪問時的方法綁定
??? 這說明所有的函數都是非數據描述符,它返回綁定或者非綁定方法依賴于它被對象還是類調用
?? ?
??? 在python中的實現如下:

class Function(object):. . .def __get__(self, obj, objtype=None):"Simulate func_descr_get() in Objects/funcobject.c"return types.MethodType(self, obj, objtype)


??? 在解釋器中展示函數描述符如何運行:

>>> class D(object):... def f(self, x):... return x...>>> d = D()>>> D.__dict__['f'] # Stored internally as a function<function f at 0x00C45070>>>> D.f # Get from a class becomes an unbound method<unbound method D.f>>>> d.f # Get from an instance becomes a bound method<bound method D.f of <__main__.D object at 0x00B18C90>>


??? 輸出說明綁定和未綁定方法是兩種不同類型,PyMethod_Type在 Objects/classobject.c 中實際的C實現是一個具有有兩種不同表現形式的單一對象,依賴于im_self是set還是null(等價C中的None)

??? 同樣,調用方法對象的效果依賴于im_self,如果set(綁定),原函數(存儲在im_func中)被調用,它的第一個參數設置為實例.
??? 如果unbound,所有的參數不做改變的傳給原函數,instancemethod_call()的C實現因為包含一些類型檢查會復雜一些

靜態方法和類方法
??? 無數據描述符提供一種簡單的機制將函數綁定為方法

??? 簡單地說,函數的__get__()方法會將函數被作為屬性訪問時轉換為方法,非數據描述符將 obj.f(*args) 調用為f(obj, *args).調用 klass.f(*args)變為f(*args)

??? 下面的表格匯總了綁定和它常見的兩種變化

??????? Transformation?? ?Called from an Object?? ?Called from a Class
??????? function?? ????   f(obj, *args)?? ????????   ?? f(*args)
??????? staticmethod??   f(*args)?? ???????????     f(*args)
??????? classmethod?? ???? f(type(obj), *args)?? ???????? f(klass, *args)

??? 調用c.f 或者 C.f等價于 object.__getattribute__(c, "f") 或者 object.__getattribute__(C, "f"),不管從對象還是類中,這個函數都可以訪問到

??? 不需要self變量的方法適合使用靜態方法
??? 例如:一個統計包可能包括用于實驗數據的容器類,該類提供了用于計算依賴于數據的平均、平均值、中值和其他描述性統計數據的常規方法.可是可能有一些概念相關但不依賴數據的函數.
??? 例如:erf(x)是一個不依賴于特定數據集的函數,它可以從一個類或者函數調用:s.erf(1.5) --> .9332 或者 Sample.erf(1.5) --> .9332

??? 靜態方法返回原始函數:

>>> class E(object):... def f(x):... print x... f = staticmethod(f)...>>> print E.f(3)3>>> print E().f(3)3


??? python版本使用非數據描述符的實現方法:

class StaticMethod(object):"Emulate PyStaticMethod_Type() in Objects/funcobject.c"def __init__(self, f):self.f = fdef __get__(self, obj, objtype=None):return self.f

?


??? 與靜態方法不同,類方法在調用函數之前先將類的引用預添加到參數列表中.調用者不管是對象還是類,這種格式是相同的

>>> class E(object):... def f(x):... print x... f = staticmethod(f)...>>> print E.f(3)3>>> print E().f(3)3


??? 這種行為在函數只需要有類引用且不關心任何底層數據的情況下是有用的,類方法的一個用途是用來創建不同的類構造器,在python2.3中,類方法dict.fromkeys()可以使用一個key的列表來創建字典,python的實現方式:

class Dict(object):. . .def fromkeys(klass, iterable, value=None):"Emulate dict_fromkeys() in Objects/dictobject.c"d = klass()for key in iterable:d[key] = valuereturn dfromkeys = classmethod(fromkeys)

?

??? 現在可以這樣創建一個字典:

>>> Dict.fromkeys('abracadabra'){'a':None, 'r':None, 'b':None, 'c':None, 'd':None}


??? classmethod()使用無數據描述符協議實現:

class ClassMethod(object):"Emulate PyClassMethod_Type() in Objects/funcobject.c"def __init__(self, f):self.f = fdef __get__(self, obj, klass=None):if klass is None:klass = type(obj)def newfunc(*args):return self.f(klass, *args)return newfunc

?

本文翻譯原文地址:https://docs.python.org/2/howto/descriptor.html#id9












轉載于:https://www.cnblogs.com/flashBoxer/p/9771797.html

總結

以上是生活随笔為你收集整理的python的__get__、__set__、__delete__(1)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 天天干夜夜看 | 免费在线观看黄色 | 午夜黄色在线观看 | 亚洲理论在线观看 | 亚洲精品美女久久久 | 日韩一级黄色大片 | 狠狠干in | 91尤物在线 | 97人妻精品一区二区三区免费 | 欧美日韩黄| 热久久中文 | 夜夜嗨视频 | 国产中文网 | 免费看的av| 日美韩av| 亚洲成人无码久久 | 日本一区免费看 | 色中文字幕在线观看 | www.蜜臀 | 成人一级大片 | 亚洲最大福利视频网 | 超碰美女在线 | 美女被c出水 | 国产无遮挡呻吟娇喘视频 | 福利网址在线观看 | 超碰免费在线观看 | 69视频污 | 中国a级大片 | 五月天婷婷综合网 | 尤物国产 | 人妻少妇偷人精品视频 | 国产成人在线观看网站 | 欧美激情图区 | h部分肌肉警猛淫文 | 免费视频中文字幕 | 日本人视频69式jzzij | 欧美日韩二三区 | www.日日| 张津瑜国内精品www在线 | 波多野结衣一区二区在线 | 欧美一区二区日韩 | 毛片资源| 成年人免费观看网站 | 日韩一区二区a片免费观看 伊人网综合在线 | 三级黄色片免费 | 欧美日韩亚洲精品一区二区 | 91精品视频网站 | 草草网址| 国产电影免费观看高清完整版视频 | 国产伦精品一区二区三区在线观看 | 骚视频在线观看 | 亚洲国产日韩在线观看 | 国产精品久久久久久久久久久新郎 | 在线观看黄色小视频 | 性生交生活影碟片 | 91在线一区二区 | 日本大尺度电影免费观看全集中文版 | 在线播放中文字幕 | 一级aaaa毛片 | 日本专区在线 | 免费无码不卡视频在线观看 | 一区二区 中文字幕 | √天堂资源在线 | 6080av| 久久96视频 | 天天天干干干 | 日本少妇中文字幕 | 91午夜影院 | tube极品少妇videos | 99久久精品国产色欲 | 国产成人无码精品久久二区三 | 欧美亚洲中文精品字幕 | 亚洲一区精品视频在线观看 | 免费av在线播放 | 99re视频在线观看 | 91一区二区在线观看 | 亚洲不卡视频在线观看 | 韩国一区二区三区四区 | 久久天天操 | 成人勉费视频 | 黄色三级三级三级三级 | 扒下小娇妻的内裤打屁股 | 国产亚洲AV无码成人网站在线 | 午夜精品免费观看 | 国产又爽又黄游戏 | 三级在线视频 | 91综合国产 | 特黄级| 鬼眼| 亚洲精品色图 | 想要xx在线观看 | 久久婷婷婷 | 亚洲在线看片 | 另类国产| 免费在线观看www | 国产女教师一区二区三区 | 领导揉我胸亲奶揉下面 | 福利视频免费 | 国产一级一片 |