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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

python中的新式类与旧式类的一些基于descriptor的概念(上)

發(fā)布時(shí)間:2023/11/28 生活经验 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 python中的新式类与旧式类的一些基于descriptor的概念(上) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
    • python中基于descriptor的一些概念(上)
      • 1. 前言
      • 2. 新式類與經(jīng)典類
        • 2.1 內(nèi)置的object對象
        • 2.2 類的方法
          • 2.2.1 靜態(tài)方法
          • 2.2.2 類方法
        • 2.3 新式類(new-style class)
          • 2.3.1 __init__方法
          • 2.3.2 __new__靜態(tài)方法
        • 2.4. 新式類的實(shí)例
          • 2.4.1 Property
          • 2.4.2 __slots__屬性
          • 2.4.3 __getattribute__方法
          • 2.4.4 實(shí)例的方法
        • 2.5 新的對象模型
          • 2.5.1 多繼承
          • 2.5.2 MRO(Method Resolution Order, 方法解析順序)
          • 2.5.3 協(xié)作式調(diào)用父類方法

python中基于descriptor的一些概念(上)

1. 前言

python在2.2版本中引入了descriptor功能,也正是基于這個(gè)功能實(shí)現(xiàn)了新式類(new-styel class)的對象模型, 同時(shí)解決了之前版本中經(jīng)典類(classic class)系統(tǒng)中出現(xiàn)的多重繼承中的MRO(Method Resolution Order)的問題, 同時(shí)引入了一些新的概念,比如classmethod, staticmethod, super,Property等,這些新功能都是基于descriptor 而實(shí)現(xiàn)的。總而言之,通過學(xué)習(xí)descriptor可以更多地了解python的運(yùn)行機(jī)制。我在這也大概寫一個(gè)匯總, 寫一下對這些東西的理解。歡迎大家討論。 在這里,為文章中使用的詞匯做一下說明: 函數(shù):指的是第一個(gè)參數(shù)不是self的函數(shù),不在類中定義的函數(shù) 方法:指是的第一個(gè)參數(shù)是self的函數(shù) 實(shí)例:類的對象,instance 對象模型:就是實(shí)現(xiàn)對象行為的整個(gè)框架,這里分為經(jīng)典和新的兩種 使用的python版本為python 2.7.2

2. 新式類與經(jīng)典類

首先來了解一下新式類與經(jīng)典類的區(qū)別,從創(chuàng)建方法上可以明顯的看出: #新式類
class C(object):
????pass
#經(jīng)典類
class B:
????pass 簡單的說,新式類是在創(chuàng)建的時(shí)候繼承內(nèi)置object對象(或者是從內(nèi)置類型,如list,dict等),而經(jīng)典類是直 接聲明的。使用dir()方法也可以看出新式類中定義很多新的屬性和方法,而經(jīng)典類好像就2個(gè): ? 這些新的屬性和方法都是從object對象中繼承過來的。

2.1 內(nèi)置的object對象

內(nèi)置的object對象是所有內(nèi)置,object對象定義了一系列特殊的方法實(shí)現(xiàn)所有對象的默認(rèn)行為。 1. __new__,__init__方法 這兩個(gè)方法是用來創(chuàng)建object的子類對象,靜態(tài)方法__new__()用來創(chuàng)建類的實(shí)例,然后再調(diào)用 __init__()來初始化實(shí)例。 2. __delattr__, __getattribute__, __setattr__方法 對象使用這些方法來處理屬性的訪問 3. __hash__, __repr__, __str__方法 print(someobj)會(huì)調(diào)用someobj.__str__(), 如果__str__沒有定義,則會(huì)調(diào)用someobj.__repr__(), __str__()和__repr__()的區(qū)別:
  • 默認(rèn)的實(shí)現(xiàn)是沒有任何作用的
  • __repr__的目標(biāo)是對象信息唯一性
  • __str__的目標(biāo)是對象信息的可讀性
  • 容器對象的__str__一般使用的是對象元素的__repr__
  • 如果重新定義了__repr__,而沒有定義__str__,則默認(rèn)調(diào)用__str__時(shí),調(diào)用的是__repr__
  • 也就是說好的編程習(xí)慣是每一個(gè)類都需要重寫一個(gè)__repr__方法,用于提供對象的可讀信息,
  • 而重寫__str__方法是可選的。實(shí)現(xiàn)__str__方法,一般是需要更加好看的打印效果,比如你要制作
  • 一個(gè)報(bào)表的時(shí)候等。
可以允許object的子類重載這些方法,或者添加新的方法。

2.2 類的方法

新的對象模型中提供了兩種類級(jí)別的方法,靜態(tài)方法和類方法,在諸多新式類的特性中,也只有類方法這個(gè) 特性, 和經(jīng)典對象模型實(shí)現(xiàn)的功能一樣。
2.2.1 靜態(tài)方法
靜態(tài)方法可以被類或者實(shí)例調(diào)用,它沒有常規(guī)方法的行為(比如綁定,非綁定,默認(rèn)的第一個(gè)self參數(shù)),當(dāng)有一 堆函數(shù)僅僅是為了一個(gè)類寫的時(shí)候,采用靜態(tài)方法聲明在類的內(nèi)部,可以提供行為上的一致性。 創(chuàng)建靜態(tài)方法的代碼如下,使用裝飾符@staticmethod進(jìn)行創(chuàng)建 : 可以看出,不管是 類調(diào)用,還是實(shí)例調(diào)用靜態(tài)方法,都是指向同一個(gè)函數(shù)對象
2.2.2 類方法
也是可以通過類和它的實(shí)例進(jìn)行調(diào)用,不過它是有默認(rèn)第一個(gè)參數(shù),叫做是類對象,一般被 命名為cls,當(dāng)然你也可以命名為其它名字,這樣就你可以調(diào)用類對象的一些操作, 代碼如下,使用裝飾符@classmethod創(chuàng)建

2.3 新式類(new-style class)

新式類除了擁有經(jīng)典類的全部特性之外,還有一些新的特性。比如__init__發(fā)生了變化, 新增了靜態(tài)方法__new__
2.3.1 __init__方法
據(jù)說在python2.4版本以前,使用新式類時(shí),如果類的初始化方法沒有定義,調(diào)用的 時(shí)候?qū)懥硕嘤嗟膮?shù),編譯器不會(huì)報(bào)錯(cuò)。我現(xiàn)在的python 2.7會(huì)報(bào)錯(cuò),還是覺得會(huì)報(bào)錯(cuò) 比較好點(diǎn),下面給出新式類和經(jīng)典類運(yùn)行這個(gè)例子的情況: ?
2.3.2 __new__靜態(tài)方法
新式類都有一個(gè)__new__的靜態(tài)方法,它的原型是object.__new__(cls[, ...]) cls是一個(gè)類對象,當(dāng)你調(diào)用C(*args, **kargs)來創(chuàng)建一個(gè)類C的實(shí)例時(shí),python的內(nèi)部調(diào)用是 C.__new__(C, *args, **kargs),然后返回值是類C的實(shí)例c,在確認(rèn) c是C的實(shí)例后,python再調(diào)用C.__init__(c, *args, **kargs)來初始化實(shí)例c。 所以調(diào)用一個(gè)實(shí)例c = C(2),實(shí)際執(zhí)行的代碼為: c = C.__new__(C, 2)
if isinstance(c, C):
????C.__init__(c, 23)#__init__第一個(gè)參數(shù)要為實(shí)例對象 object.__new__()創(chuàng)建的是一個(gè)新的,沒有經(jīng)過初始化的實(shí)例。當(dāng)你重寫__new__方法時(shí),可以不 用使用裝飾符@staticmethod指明它是靜態(tài)函數(shù),解釋器會(huì)自動(dòng)判斷這個(gè)方法為靜態(tài)方法。如果 需要重新綁定C.__new__方法時(shí),只要在類外面執(zhí)行C.__new__ = staticmethod(yourfunc)就可以了。 可以使用__new__來實(shí)現(xiàn)Singleton單例模式: class Singleton(object):
????_singletons = {}
????def __new__(cls):
????????if not cls._singletons.has_key(cls):????????????#若還沒有任何實(shí)例
????????????cls._singletons[cls] = object.__new__(cls)??#生成一個(gè)實(shí)例
????????return cls._singletons[cls]?????????????????????????????#返回這個(gè)實(shí)例 運(yùn)行結(jié)果如下: ? 使用id()操作,可以看到兩個(gè)實(shí)例指向同一個(gè)內(nèi)存地址。Singleton的所有子類也有這一 特性,只有一個(gè)實(shí)例對象,如果它的子類定義了__init__()方法,那么必須保證它的 __init__方法能夠安全的同一個(gè)實(shí)例進(jìn)行多次調(diào)用。 ?

2.4. 新式類的實(shí)例

除了新式類本身具有新的特性外,新式類的實(shí)例也具有新的特性。比如它擁有Property功能,該 功能會(huì)對屬性的訪問方式產(chǎn)生影響;還有__slots__新屬性,該屬性會(huì)對生成子類實(shí)例產(chǎn)生影響;還 添加了一個(gè)新的方法__getattribute__,比原有的__getattr__更加通用。
2.4.1 Property
在介紹完descriptor會(huì)回過頭來講這個(gè)。
2.4.2 __slots__屬性
通常每一個(gè)實(shí)例x都會(huì)有一個(gè)__dict__屬性,用來記錄實(shí)例中所有的屬性和方法,也是通過這個(gè)字典, 可以讓實(shí)例綁定任意的屬性。而__slots__屬性作用就是,當(dāng)類C有比較少的變量,而且擁有__slots__屬性時(shí), 類C的實(shí)例 就沒有__dict__屬性,而是把變量的值存在一個(gè)固定的地方。如果試圖訪問一個(gè)__slots__中沒有 的屬性,實(shí)例就會(huì)報(bào)錯(cuò)。這樣操作有什么好處呢?__slots__屬性雖然令實(shí)例失去了綁定任意屬性的便利, 但是因?yàn)槊恳粋€(gè)實(shí)例沒有__dict__屬性,卻能有效節(jié)省每一個(gè)實(shí)例的內(nèi)存消耗,有利于生成小而精 干的實(shí)例。 為什么需要這樣的設(shè)計(jì)呢? 在一個(gè)實(shí)際的企業(yè)級(jí)應(yīng)用中,當(dāng)一個(gè)類生成上百萬個(gè)實(shí)例時(shí),即使一個(gè)實(shí)例節(jié)省幾十個(gè)字節(jié)都可以節(jié)省 一大筆內(nèi)存,這種情況就值得使用__slots__屬性。 怎么去定義__slots__屬性?
__slots__是一個(gè)類變量,__slots__屬性可以賦值一個(gè)包含類屬性名的字符串元組,或者是可迭代變量,或者 是一個(gè)字符串,只要在類定義的時(shí)候,使用__slots=aTuple來定義該屬性就可以了: 可以看出實(shí)例a中沒有__dict__字典,而且不能隨意添加新的屬性,不定義__slots__是可以隨意添加的: 使用時(shí)__slots__時(shí)需要注意的幾點(diǎn): 1.? 當(dāng)一個(gè)類的父類沒有定義__slots__屬性,父類中的__dict__屬性總是可以訪問到的,所以只在子 類中定義__slots__屬性,而不在父類中定義是沒有意義的。 2. 如果定義了__slots屬性,還是想在之后添加新的變量,就需要把'__dict__'字符串添加到__slots__的 元組里。 3. 定義了__slots__屬性,還會(huì)消失的一個(gè)屬性是__weakref__,這樣就不支持實(shí)例的weak reference, 如果還是想用這個(gè)功能,同樣,可以把'__weakref__'字符串添加到元組里。 4. __slots__功能是通過descriptor實(shí)現(xiàn)的,會(huì)為每一個(gè)變量創(chuàng)建一個(gè)descriptor。 5. __slots__的功能只影響定義它的類,因此,子類需要重新定義__slots__才能有它的功能。
2.4.3 __getattribute__方法
對新式類的實(shí)例來說,所有屬性和方法的訪問操作都是通過__getattribute__完成, 這是由object基類實(shí)現(xiàn)的。如果有特殊的要求,可以重載__getattribute__方法,下面 實(shí)現(xiàn)一個(gè)不能使用append方法的list: ??
2.4.4 實(shí)例的方法
經(jīng)典的與新的對象模型都允許一個(gè)實(shí)例擁有私有的屬性和方法(可以通過綁定和重綁定)。實(shí)例 的私有屬性會(huì)覆蓋掉類中定義的同名屬性,舉例說明: ? 然而在python中,隱式調(diào)用實(shí)例的私有特殊方法時(shí),新的對象模型和經(jīng)典對象模型表現(xiàn)上不太一樣。 在經(jīng)典對象模型中,無論是顯示調(diào)用還是隱式調(diào)用特殊方法,都會(huì)調(diào)用實(shí)例中后綁定的特殊方法。 而在新的對象模型中,除非顯式地調(diào)用實(shí)例的特殊方法,否則python總是會(huì)去調(diào)用類中定義的特殊方法, 如果沒有定義的話,就報(bào)錯(cuò)。代碼如下: 經(jīng)典類: ? 新式類: ?? 調(diào)用a[1],將產(chǎn)生一個(gè)隱式的__getitem__方法的調(diào)用,在新式類中,因?yàn)轭愔袥]有定義這個(gè)方法,也不是 object基類有的方法,所以報(bào)錯(cuò)。需要顯示地調(diào)用才可以運(yùn)行。

2.5 新的對象模型

在新的對象模型中,繼承方式和經(jīng)典對象模型大體相同,一個(gè)關(guān)鍵的區(qū)別就是新式類能夠從python的內(nèi)置 類型中繼承,而經(jīng)典類不行。
2.5.1 多繼承
新式類同樣支持多繼承,但是如果新式類想要從多個(gè)內(nèi)置類型中繼承生成一個(gè)新類的話,則這些內(nèi)置類必須是 經(jīng)過精心設(shè)計(jì),能夠互相兼容的。顯然,python也沒會(huì)讓你隨意的從多個(gè)內(nèi)置類中進(jìn)行多繼承,想創(chuàng)建一個(gè)超級(jí)類 不是那么容易的。。。通常情況下,至多可以繼承一個(gè)內(nèi)置類,比如list, set, dict等。
2.5.2 MRO(Method Resolution Order, 方法解析順序)
對于下圖的多繼承關(guān)系: b = A(),當(dāng)調(diào)用b.a的時(shí)候會(huì)發(fā)生什么事呢? 在經(jīng)典對象模型中,方法和屬性的查找鏈?zhǔn)前凑諒淖蟮接?#xff0c;深度優(yōu)先的方式進(jìn)行查找。所以當(dāng)A的實(shí)例b 要使用屬性a時(shí),它的查找順序?yàn)?A->B->D->C->A,這樣做就會(huì)忽略類C的定義a,而先找到的基類D的 屬性a,這是一個(gè)bug,這個(gè)問題在新式類中得到修復(fù),新的對象模型采用的是從左到右,廣度優(yōu)先的方式 進(jìn)行查找,所以查找順序?yàn)锳->B->C->D,可以正確的返回類C的屬性a。 經(jīng)典類: 新式類: ?? 這個(gè)順序的實(shí)現(xiàn)是通過新式類中特殊的只讀屬性__mro__,類型是一個(gè)元組,保存著解析順序信息。只能通過 類來使用,不能通過實(shí)例調(diào)用。 順序還和繼承時(shí),括號(hào)中寫的父類順序有關(guān):
2.5.3 協(xié)作式調(diào)用父類方法
當(dāng)子類重寫了父類的一個(gè)方法時(shí),通常會(huì)調(diào)用父類的同名方法做一些工作,這是比較常見的使用 方式--使用非綁定語法來調(diào)用父類的方法。不過在多繼承中,這種方法有缺餡: 可以看到,基類A的方法重復(fù)運(yùn)行了兩次。怎樣才能確保父類中的方法只被順序的調(diào)用一次呢? 在新的對象系統(tǒng)中,有一種特殊的方法super(aclass, obj),可以返回obj實(shí)例的一個(gè)特殊類型 superobject(超對象, 不是簡單的父類的對象),當(dāng)我們使用超對象調(diào)用父類的方法時(shí),就 能保證只被運(yùn)行一次: 可以看到,D的父類中所有的foo方法都得到執(zhí)行,并且基類A的foo方法只執(zhí)行了一次。如果養(yǎng)成了 使用super去調(diào)用父類方法的習(xí)慣,那么你的類就可以適應(yīng)無論多么復(fù)雜的繼承調(diào)用結(jié)構(gòu)。super() 可以看成是更加安全調(diào)用父類方法的一種新方式。

轉(zhuǎn)載自:

作者:btchenguang 出處:http://www.cnblogs.com/btchenguang/

總結(jié)

以上是生活随笔為你收集整理的python中的新式类与旧式类的一些基于descriptor的概念(上)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。