python面向?qū)ο笸耆崂?/h1>

前言

python面向?qū)ο蠛蚃ava有不少區(qū)別便监,加之兩個(gè)大版本2和3又有區(qū)別阅束,所以很容易造成困惑细疚,本篇文章來針對(duì)這些容易搞混的概念進(jìn)行一個(gè)全面的梳理躁垛。內(nèi)容主要來自官網(wǎng)文檔的整理,放心食用洲鸠。

類型(type)堂淡、類 (class)、對(duì)象(object)

對(duì)象 Object

python中一切都是對(duì)象(object)。為什么這么說呢绢淀,從邏輯上來講萤悴,所有的東西首先他得是個(gè)‘東西’,從python的實(shí)現(xiàn)來講因?yàn)樗袞|西都是object這個(gè)類的實(shí)例更啄。object是一個(gè)特殊的最原始(primitive)的內(nèi)置類型稚疹。(注意這是python2.2之后達(dá)到的效果居灯,后文會(huì)講祭务。)

類型 type

所有的對(duì)象都有id、類型怪嫌、數(shù)值(value)這三個(gè)屬性义锥。也就是說type是對(duì)象的一個(gè)屬性。type屬性決定了對(duì)象支持的操作以及可能的取值岩灭。
python的標(biāo)準(zhǔn)類型包括:
None拌倍、NotImplemeted、Ellipsis噪径、Sequences柱恤、Set、Callable找爱、Mappings梗顺、Modules、Classes车摄、Class instances寺谤、Files 以及解釋器使用的內(nèi)部類型包括Code對(duì)象、Frame對(duì)象吮播、Traceback對(duì)象等变屁。具體參考https://docs.python.org/3.7/reference/datamodel.html#objects-values-and-types

除了內(nèi)置的type,Python還有很多內(nèi)置函數(shù)意狠。type()就是其一粟关。type(x) 返回x的type屬性值。那type自己也是一個(gè)對(duì)象环戈,他的屬性是啥呢誊役,還是type。因?yàn)閠ype是最原始(primitive)的類型谷市。

類 class

class也是一個(gè)對(duì)象蛔垢。這和Java是一致的。只不過這個(gè)對(duì)象有他的特殊性:class同時(shí)也是一種內(nèi)置類型迫悠,且是一種callable的類型鹏漆。通過調(diào)用class的__call__()方法和得到該類的實(shí)例對(duì)象。class是制造object的一種特殊object。在python2.2之后用戶定義的class 就是一個(gè)type艺玲,是元初type的實(shí)例括蝠。

object和type的關(guān)系:

object和type是python里最原始的兩個(gè)東西》咕郏可以看成是開天辟地的存在忌警。

在面向?qū)ο篌w系里面,存在兩種關(guān)系:

  • 父子關(guān)系秒梳,即繼承關(guān)系法绵,表現(xiàn)為子類繼承于父類,如『蛇』類繼承自『爬行動(dòng)物』類酪碘,我們說『蛇是一種爬行動(dòng)物』朋譬,英文說『snake is a kind of reptile』。在python里要查看一個(gè)類型的父類兴垦,使用它的__bases__屬性可以查看徙赢。

  • 類型實(shí)例關(guān)系,表現(xiàn)為某個(gè)類型的實(shí)例化探越,例如『萌萌是一條蛇』狡赐,英文說『萌萌 is an instance of snake』。在python里要查看一個(gè)實(shí)例的類型钦幔,可使用type()函數(shù)查看枕屉。

從邏輯上來講 type的基類是object,而object的類型是type节槐,是個(gè)先有雞還是先有蛋的問題搀庶。先有object還是先有type沒法說,obejct和type是共生的關(guān)系铜异,必須同時(shí)出現(xiàn)的哥倔。

在Python的世界中,object是父子關(guān)系的頂端揍庄,所有的數(shù)據(jù)類型的父類都是它咆蒿;type是類型實(shí)例關(guān)系的頂端,所有對(duì)象都是它的實(shí)例的蚂子。它們兩個(gè)的關(guān)系可以這樣描述:

  • object是一個(gè)type沃测,object is and instance of type。即object是type的一個(gè)實(shí)例食茎。
  • type是一種object蒂破, type is kind of object。即type是object的子類别渔。
image.png

這里推薦看這個(gè)知乎回答 https://www.zhihu.com/question/38791962/answer/78172929
是對(duì)python官網(wǎng)推薦文章types and objects的整理附迷。英文原文Python Types and Objects

PS:

這里我看了一下源碼:

class object:
...
   __class__ = None # (!) forward: type, real value is ''
...

object的class在代碼里是None惧互,然后注釋說其實(shí)是type,應(yīng)該是cpython實(shí)現(xiàn)的時(shí)候改了喇伯。所以硬要說先有誰的話喊儡,應(yīng)該是先有object。

定義type的時(shí)候就是直接繼承自object:

class type(object):
    """
    type(object) -> the object's type
    type(name, bases, dict) -> a new type
    """
    def mro(self): # real signature unknown; restored from __doc__
        """
        mro() -> list
        return a type's method resolution order
        """
   ...

None的定義是, 可以看到他的類型也是底層實(shí)現(xiàn)改了稻据。

None = object() # real value of type <type 'NoneType'> replaced

看一下實(shí)際輸出:

print (type(object))
<class 'type'>
print (type(type))
<class 'type'>
print (type.__bases__)
(<class 'object'>,)
print (object.__bases__)
()

有時(shí)間了解一下cpython也許能了解的更徹底些艾猜。

新式類和舊式類

在python中class分兩種,新式類(new-style class)和舊式類(classic class)捻悯。

在python2.1及之前的版本中只有舊式類匆赃,class和type是兩套體系∏锒龋考慮一個(gè)用戶的定義的對(duì)象x炸庞,x.__class__返回他的類钱床,type(x)返回他的類型 荚斯,是個(gè)固定值 ‘<type 'instance'>’。也就是說舊式類的實(shí)例化和他的類沒有關(guān)系查牌,都是通過內(nèi)置的Instance類型實(shí)現(xiàn)的。

這和內(nèi)置對(duì)象是不同的,int對(duì)象的類型就是int湿刽,同時(shí)int()返回的也是int類型的對(duì)象怀读,內(nèi)置對(duì)象和自定義對(duì)象不同就對(duì)代碼統(tǒng)一實(shí)現(xiàn)帶來很大困難。

比如說有段代碼輸入一個(gè)對(duì)象胁孙,返回一個(gè)默認(rèn)構(gòu)造的同類型對(duì)象唠倦,本來應(yīng)該寫作type(obj)(),現(xiàn)在就必須寫成:obj.class() if hasattr(obj, 'class') else type(obj)()涮较。如果想用自定義的類去替代一些系統(tǒng)內(nèi)置類型稠鼻,比如說自定義一個(gè)dictionary,這樣的不一致就會(huì)出問題狂票。

Python在Python 2.2中引入了新式類候齿,統(tǒng)一了類和類型的概念。新式類就是用戶定義的類型闺属。如果x是一個(gè)新式類的實(shí)例慌盯,那么type(x)默認(rèn)情況下與x.__class__相同。

新式類之后自定義類和內(nèi)置類型就一致了:

  1. 所有類型的類型都是type
  2. 所有類型調(diào)用的結(jié)果都是構(gòu)造掂器,返回這個(gè)類型的實(shí)例
  3. 所有類型都是object的子類

這樣就不再需要區(qū)分自定義類和類型了亚皂。也就是前文說的,用戶定義的class就是一個(gè)type的實(shí)例国瓮。

Python2 和 Python3 中面向?qū)ο蟮膮^(qū)別

在python2中灭必,出于兼容性考慮匠楚,所有的類默認(rèn)仍然是舊式類,聲明新式類的方法是顯示的繼承一個(gè)新式類:object厂财。
python3中芋簿,舊式類被移除了,所有的類都是新式類璃饱。所以聲明類的時(shí)候不需要顯示的繼承object了与斤,默認(rèn)就是繼承object的。

元類 metaclass

元類(metaclass)是Python 2.2中引入的概念荚恶,它的作用是定制類的創(chuàng)建行為撩穿。type是默認(rèn)的元類。

默認(rèn)情況下谒撼,class是由type()函數(shù)創(chuàng)建食寡,創(chuàng)建時(shí)會(huì)為class中的代碼定義新的命名空間并將函數(shù)名同type(name, bases, namespace)的結(jié)果進(jìn)行綁定。

在創(chuàng)建類時(shí)廓潜,通過傳入metaclass這個(gè)參數(shù)抵皱,或者繼承一個(gè)有這個(gè)參數(shù)的類 ,可以改變類的創(chuàng)建過程辩蛋。

class Meta(type):
    pass

class MyClass(metaclass=Meta):
    pass

class MySubclass(MyClass):
    pass

看個(gè)例子呻畸,這個(gè)metaclass可以給我們自定義的MyList增加一個(gè)add方法:

定義ListMetaclass,按照默認(rèn)習(xí)慣悼院,metaclass的類名總是以Metaclass結(jié)尾伤为,以便清楚地表示這是一個(gè)metaclass:

# metaclass是類的模板,所以必須從`type`類型派生:
class ListMetaclass(type):
    def __new__(cls, name, bases, attrs):
        attrs['add'] = lambda self, value: self.append(value)
        return type.__new__(cls, name, bases, attrs)

有了ListMetaclass据途,我們?cè)诙x類的時(shí)候還要指示使用ListMetaclass來定制類绞愚,傳入關(guān)鍵字參數(shù)metaclass:

class MyList(list, metaclass=ListMetaclass):
    pass

當(dāng)我們傳入關(guān)鍵字參數(shù)metaclass時(shí),魔術(shù)就生效了颖医,它指示Python解釋器在創(chuàng)建MyList時(shí)位衩,要通過ListMetaclass.new()來創(chuàng)建,在此便脊,我們可以修改類的定義蚂四,比如,加上新的方法哪痰,然后遂赠,返回修改后的定義。

__new__()方法接收到的參數(shù)依次是:

  • 當(dāng)前準(zhǔn)備創(chuàng)建的類的對(duì)象晌杰;

  • 類的名字跷睦;

  • 類繼承的父類集合;

  • 類的方法集合肋演。

測(cè)試一下MyList是否可以調(diào)用add()方法:

>>> L = MyList()
>>> L.add(1)
>> L
[1]

而普通的list沒有add()方法:

>>> L2 = list()
>>> L2.add(1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'list' object has no attribute 'add'

(注意抑诸,百分之99的工程中不會(huì)用到自定義元類烂琴,除非你對(duì)元類非常理解)

參考

Python新式類,統(tǒng)一了類型機(jī)制的理解蜕乡?
Python 的 type 和 object 之間是怎么一種關(guān)系奸绷?
https://docs.python.org/3.7/reference/datamodel.html#objects-values-and-types
https://www.liaoxuefeng.com/wiki/1016959663602400/1017592449371072

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者

  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市层玲,隨后出現(xiàn)的幾起案子号醉,更是在濱河造成了極大的恐慌,老刑警劉巖辛块,帶你破解...
    沈念sama閱讀 222,104評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件畔派,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡润绵,警方通過查閱死者的電腦和手機(jī)线椰,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,816評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來尘盼,“玉大人憨愉,你說我怎么就攤上這事』谶矗” “怎么了莱衩?”我有些...
    開封第一講書人閱讀 168,697評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵爵嗅,是天一觀的道長娇澎。 經(jīng)常有香客問我,道長睹晒,這世上最難降的妖魔是什么趟庄? 我笑而不...
    開封第一講書人閱讀 59,836評(píng)論 1 298
  • 正文 為了忘掉前任,我火速辦了婚禮伪很,結(jié)果婚禮上戚啥,老公的妹妹穿的比我還像新娘。我一直安慰自己锉试,他們只是感情好猫十,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,851評(píng)論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著呆盖,像睡著了一般拖云。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上应又,一...
    開封第一講書人閱讀 52,441評(píng)論 1 310
  • 那天宙项,我揣著相機(jī)與錄音,去河邊找鬼株扛。 笑死尤筐,一個(gè)胖子當(dāng)著我的面吹牛汇荐,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播盆繁,決...
    沈念sama閱讀 40,992評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼掀淘,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了油昂?” 一聲冷哼從身側(cè)響起繁疤,我...
    開封第一講書人閱讀 39,899評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎秕狰,沒想到半個(gè)月后稠腊,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,457評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡鸣哀,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,529評(píng)論 3 341
  • 正文 我和宋清朗相戀三年架忌,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片我衬。...
    茶點(diǎn)故事閱讀 40,664評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡叹放,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出挠羔,到底是詐尸還是另有隱情井仰,我是刑警寧澤,帶...
    沈念sama閱讀 36,346評(píng)論 5 350
  • 正文 年R本政府宣布破加,位于F島的核電站俱恶,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏范舀。R本人自食惡果不足惜合是,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,025評(píng)論 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望锭环。 院中可真熱鬧聪全,春花似錦、人聲如沸辅辩。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,511評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽玫锋。三九已至蛾茉,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間景醇,已是汗流浹背臀稚。 一陣腳步聲響...
    開封第一講書人閱讀 33,611評(píng)論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留三痰,地道東北人吧寺。 一個(gè)月前我還...
    沈念sama閱讀 49,081評(píng)論 3 377
  • 正文 我出身青樓窜管,卻偏偏與公主長得像,于是被迫代替她去往敵國和親稚机。 傳聞我的和親對(duì)象是個(gè)殘疾皇子幕帆,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,675評(píng)論 2 359