最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Python中的類與對象之描述符詳解

 更新時間:2015年03月27日 17:34:09   作者:Obi Ike-Nwosu  
這篇文章主要介紹了Python中的描述符詳解,屬于Python學習過程中類與對象的基本知識,需要的朋友可以參考下

描述符(Descriptors)是Python語言中一個深奧但卻重要的一部分。它們廣泛應用于Python語言的內核,熟練掌握描述符將會為Python程序員的工具箱添加一個額外的技巧。為了給接下來對描述符的討論做一些鋪墊,我將描述一些程序員可能會在日常編程活動中遇到的場景,然后我將解釋描述符是什么,以及它們如何為這些場景提供優(yōu)雅的解決方案。在這篇總結中,我會使用新樣式類來指代Python版本。

1、假設一個程序中,我們需要對一個對象屬性執(zhí)行嚴格的類型檢查。然而,Python是一種動態(tài)語言,所以并不支持類型檢查,但是這并不妨礙我們實現自己版本,且較為初級的類型檢查。對象屬性類型檢查的傳統(tǒng)方法可能采用下面的方式:

def __init__(self, name, age):
 if isinstance(str, name):
 self.name = name
 else:
 raise TypeError("Must be a string")
 if isinstance(int, age):
 self.age = age
 else:
 raise TypeError("Must be an int")

上面是執(zhí)行這種類型檢查的一種方法,但是參數數量增加時它將變得比較繁瑣。另外,在賦值之前,我們可以創(chuàng)建一個在__init__中調用的type_check(type, val)函數,但是當我們想在其他地方設置屬性值時,該如何簡單地實現這種檢查呢。我想到的一個快速解決方案是Java中的getters和setters,但是這并不符合Python風格,并且比較麻煩。

2、假設在一個程序中,我們想創(chuàng)建一些在運行時立刻初始化然后變成只讀的屬性。有人也能想到利用Python中的特殊方法來實現,但這種實現方法仍舊是笨拙和繁瑣的。

3、最后,設想一個程序中,我們希望以某種方式自定義對象屬性的訪問。例如需要記錄這種屬性的訪問。同樣的,還是可以想到一個解決方法,即使這種解決方案可能比較笨重并且不可復用。

上述問題因都與屬性引用相關而全部聯系在了一起。下面,我們將嘗試自定義屬性的訪問方法。
Python描述符

針對上面所列的問題,描述符提供了優(yōu)雅、簡潔、健壯和可重用的解決方案。簡而言之,一個描述符就是一個對象,該對象代表了一個屬性的值。這就意味著如果一個賬戶對象有一個屬性“name”,那么描述符就是另一個能夠用來代表屬性“name”持有值的對象。描述符協(xié)議中“定義了__get__”、“__set__”或”__delete__” 這些特殊方法,描述符是實現其中一個或多個方法的對象。這些方法中每一種方法的簽名如下所示:

python descr.get(self,obj,type=None)->value。
 
descr.__set__(self, obj, value) --> None
 
descr.__delete__(self, obj) --> None

實現__get__方法的對象是非數據描述符,意味著在初始化之后它們只能被讀取。而同時實現__get__和__set__的對象是數據描述符,意味著這種屬性是可寫的。

為了更好地理解描述符,我們給出針對上述問題基于描述符的解決方法。使用Python描述符實現對象屬性的類型檢查將是一個非常簡單的任務。裝飾器實現這種類型檢查的代碼如下所示:

class TypedProperty(object):
 
 def __init__(self, name, type, default=None):
 self.name = "_" + name
 self.type = type
 self.default = default if default else type()
 
 def __get__(self, instance, cls):
 return getattr(instance, self.name, self.default)
 
 def __set__(self,instance,value):
 if not isinstance(value,self.type):
 raise TypeError("Must be a %s" % self.type)
 setattr(instance,self.name,value)
 
 def __delete__(self,instance):
 raise AttributeError("Can't delete attribute")
 
class Foo(object):
 name = TypedProperty("name",str)
 num = TypedProperty("num",int,42)
 
>> acct = Foo()
>> acct.name = "obi"
>> acct.num = 1234
>> print acct.num
1234
>> print acct.name
obi
# trying to assign a string to number fails
>> acct.num = '1234'
TypeError: Must be a <type 'int'>

在這個例子中,我們實現了一個描述符TypedProperty,并且這個描述符類會對它所代表的類的任何屬性執(zhí)行類型檢查。注意到這一點很重要,即描述符只能在類級別進行合法定義,而不能在實例級別定義。例如,在上面例子中的__init__方法里。

當訪問類Foo實例的任何屬性時,描述符會調用它的__get__方法。需要注意的是,__get__方法的第一個參數是描述符代表的屬性被引用的源對象。當屬性被分配時,描述符會調用它的__set__方法。為了理解為什么可以使用描述符代表對象屬性,我們需要理解Python中屬性引用解析的執(zhí)行方式。對于對象來說,屬性解析機制在object.__getattribute__()中。該方法將b.x轉換成type(b).__dict__['x'].__get__(b, type(b))。然后,解析機制使用優(yōu)先級鏈搜索屬性,在優(yōu)先級鏈中,類字典中發(fā)現的數據描述符的優(yōu)先級高于實例變量,實例變量優(yōu)先級高于非數據描述符,如果提供了getattr(),優(yōu)先級鏈會為getattr()分配最低優(yōu)先級。對于一個給定的對象類,可以通過自定義__getattribute__方法來重寫優(yōu)先級鏈。

深刻理解優(yōu)先級鏈之后,就很容易想出針對前面提出的第二個和第三個問題的優(yōu)雅解決方案了。那就是,利用描述符實現一個只讀屬性將變成實現數據描述符這個簡單的情況了,即不帶__set__方法的描述符。盡管在本例中不重要,定義訪問方式的問題只需要在__get__和__set__方法中增加所需的功能即可。
類屬性

每次我們想使用描述符的時候都不得不定義描述符類,這樣看起來非常繁瑣。Python特性提供了一種簡潔的方式用來向屬性增加數據描述符。一個屬性簽名如下所示:
 

property(fget=None, fset=None, fdel=None, doc=None) -> property attribute

fget、fset和fdel分別是類的getter、setter和deleter方法。我們通過下面的一個示例來說明如何創(chuàng)建屬性:

class Accout(object):
 def __init__(self):
 self._acct_num = None
 
 def get_acct_num(self):
 return self._acct_num
 
 def set_acct_num(self, value):
 self._acct_num = value
 
 def del_acct_num(self):
 del self._acct_num
 
 acct_num = property(get_acct_num, set_acct_num, del_acct_num, "Account number property.")

如果acct是Account的一個實例,acct.acct_num將會調用getter,acct.acct_num = value將調用setter,del acct_num.acct_num將調用deleter。

在Python中,屬性對象和功能可以像《描述符指南》中說明的那樣使用描述符協(xié)議來實現,如下所示:

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

Python也提供了@ property裝飾器,可以用它來創(chuàng)建只讀屬性。一個屬性對象擁有getter、setter和deleter裝飾器方法,可以使用它們通過對應的被裝飾函數的accessor函數創(chuàng)建屬性的拷貝。下面的例子最好地解釋了這一點:

class C(object):
 def __init__(self):
 self._x = None
 
 @property
 # the x property. the decorator creates a read-only property
 def x(self):
 return self._x
 
 @x.setter
 # the x property setter makes the property writeable
 def x(self, value):
 self._x = value
 
 @x.deleter
 def x(self):
 del self._x

如果我們想讓屬性只讀,那么我們可以去掉setter方法。

在Python語言中,描述符有著廣泛的應用。Python函數、類方法、靜態(tài)方法都是非數據描述符的例子。針對列舉的Python對象是如何使用描述符實現的問題,《描述符指南》給出了一個基本的描述。

相關文章

  • python 插入日期數據到Oracle實例

    python 插入日期數據到Oracle實例

    這篇文章主要介紹了python 插入日期數據到Oracle實例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-03-03
  • Pytorch轉onnx、torchscript方式

    Pytorch轉onnx、torchscript方式

    這篇文章主要介紹了Pytorch轉onnx、torchscript方式,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-05-05
  • Python獲取Windows或Linux主機名稱通用函數分享

    Python獲取Windows或Linux主機名稱通用函數分享

    這篇文章主要介紹了Python獲取Windows或Linux主機名稱通用函數分享,本文直接給出實現代碼,需要的朋友可以參考下
    2014-11-11
  • python logging模塊的使用詳解

    python logging模塊的使用詳解

    這篇文章主要介紹了python logging模塊的使用,幫助大家更好的理解和使用python,感興趣的朋友可以了解下
    2020-10-10
  • 如何利用Python保留指定位數的小數

    如何利用Python保留指定位數的小數

    這篇文章主要給大家介紹了關于如何利用Python保留指定位數的小數,,代碼簡單易懂,非常不錯,對大家學習或者使用Python具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-08-08
  • 通過python將大量文件按修改時間分類的方法

    通過python將大量文件按修改時間分類的方法

    今天小編就為大家分享一篇通過python將大量文件按修改時間分類的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-10-10
  • Pytho的HTTP交互httpx包模塊使用詳解

    Pytho的HTTP交互httpx包模塊使用詳解

    Python 的 httpx 包是一個用于 HTTP 交互的一個優(yōu)秀且靈活的模塊。本文進行詳細的講解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-03-03
  • Python使用Turtle圖形函數畫圖顏色填充實例

    Python使用Turtle圖形函數畫圖顏色填充實例

    這篇文章主要介紹了Python使用Turtle圖形函數畫圖顏色填充實例,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-08-08
  • 在pycharm中關掉ipython console/PyDev操作

    在pycharm中關掉ipython console/PyDev操作

    這篇文章主要介紹了在pycharm中關掉ipython console/PyDev操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-06-06
  • 一步步教你用python的scrapy編寫一個爬蟲

    一步步教你用python的scrapy編寫一個爬蟲

    這篇文章主要給大家介紹了如何利用python的scrapy編寫一個爬蟲的相關資料,文中通過示例代碼介紹的非常詳細,對大家學習或者使用scrapy具有一定的參考學習價值,需要的朋友們下面來一起學習學習吧
    2019-04-04

最新評論

巨鹿县| 萨嘎县| 太白县| 海盐县| 锦州市| 江源县| 福鼎市| 舟曲县| 教育| 上思县| 庄河市| 临沭县| 汤阴县| 清徐县| 梁平县| 含山县| 呼图壁县| 海兴县| 南澳县| 镇巴县| 广河县| 宝丰县| 新津县| 海城市| 松桃| 随州市| 文昌市| 高安市| 玉林市| 鲁山县| 宁津县| 乾安县| 房山区| 商都县| 霍城县| 永城市| 山西省| 历史| 南召县| 岳阳市| 江陵县|