程序設(shè)計(jì)中“面向?qū)ο?/strong>”是個(gè)老生常談的話題视哑,而Python則把“對象”發(fā)揮到了極致!
那究竟什么是“對象”誊涯?
我認(rèn)為挡毅,一切可名狀或不可名狀之物皆可以稱之為“對象”!世界是由對象組成的暴构,世界本身也是一個(gè)對象跪呈。Python的世界秉承的正是這樣的理念——一切皆對象——字符段磨、數(shù)字、列表耗绿、元組苹支、集合、字典误阻、函數(shù)债蜜、類、模塊究反、某種操作寻定、甚至Python本身,等等都是對象精耐。
在某些編程語言中特姐,“對象”的定義較為苛刻,比如要求對象必須有“屬性attribute”和“方法method”黍氮,或者對象必須可以子類化唐含。而Python則更為寬容,沒有這樣那樣的限制沫浆,它既包含狹義的對象捷枯,同時(shí)也將其他元素當(dāng)成對象來對待。
那么Python究竟是怎么通過具體方式來體現(xiàn)“萬物皆對象”的邏輯的呢专执?有沒有更直觀的理解方式淮捆?當(dāng)然有!答案就是:
“Python本股, 一切都可以賦值攀痊!”
沒錯(cuò),一切都可以賦值拄显!也就是可以執(zhí)行‘=’操作苟径。變量可以賦值、屬性可以賦值躬审、方法可以賦值棘街、函數(shù)可以賦值、任何一種操作都可以賦值承边,即使很多時(shí)候這種賦值沒有任何實(shí)際意義遭殉,但依然可以賦值!
舉個(gè)例子博助,對于列表a=[1,2,3]险污,a.append(4)表示調(diào)用列表方法把4加入到a的末尾作為第四個(gè)元素,它純粹是一種操作富岳,沒有返回值蛔糯。因此里伯,如果寫成b=a.append(4),除了詮釋一下畫蛇添足渤闷,并沒有其他實(shí)際意義。然而神奇的Python告訴你:“沒錯(cuò)脖镀,你可以這樣干飒箭,因?yàn)槲野補(bǔ).append(4)這一操作過程也當(dāng)成了對象,既然是對象蜒灰,在我們Python的世界里那就是可以賦值的弦蹂。不過我還想告訴你,這樣的賦值對于完成你的工作沒啥意義强窖,因?yàn)檫@里的b啥也不是凸椿,但真的不影響我把他當(dāng)對象!”翅溺。
看下面的代碼顯得更清楚脑漫。可見b的值是‘None’咙崎,而類型是‘None Type’优幸,這意味著b沒啥實(shí)際含義,但即使這樣褪猛,Python還是一視同仁地給它分配了地址网杆!深深地愛意,有沒有伊滋?還可以繼續(xù)賦值c = d碳却,因?yàn)槎际菍ο舐铩?/p>
>>>a = [1,2,3]
>>>b = a.append(4)
>>>print('a={},type(a):{}'.format(a,type(a)))
>>>print('b={},type(b):{}'.format(b,type(b)))
>>>print('id(b)={}'.format(id(b)))
a=[1, 2, 3, 4],type(a):<class 'list'>
b=None,type(b):<class 'NoneType'>
id(b)=1464837264
“Python,一切皆可以賦值”還有另一種表述:
“Python笑旺, 一切皆有“類型(type)”昼浦!
關(guān)于“類型”,int筒主、string座柱、list、tuple物舒、set色洞、dict、bool這些最基本的就不再啰嗦了冠胯,除此以外火诸,還有各種各樣稀奇古怪的類型,如前面提到的‘None Type’荠察,對置蜀,它也屬于一種獨(dú)立的“類型”(這就好像數(shù)字0奈搜,雖然啥也沒有,但它也是個(gè)數(shù)字岸⒒纭)馋吗。Python對象都有“類型”,各種第三方庫也都有自己各式各樣的“類型”秋秤,用戶甚至可以定義自己的“類型”宏粤。
在python中有一個(gè)非常有用的內(nèi)置函數(shù):type(),它可以返回對象的具體類型灼卢。
比如type(None)绍哎,可見關(guān)鍵字‘None’的類型就是‘NoneType’。
>>>type(None)
NoneType
再比如type(type)鞋真,可見函數(shù)type自己就是一個(gè)‘type’類型崇堰,這有點(diǎn)兒繞啊。
>>>type(type)
type
再比如內(nèi)置求最大值函數(shù)“max”涩咖,從下面的代碼可以看出函數(shù)‘max’本身的類型是builtin_function_or_method海诲;而‘max()’的類型實(shí)際表示了返回值的類型;如果直接type(max())則會(huì)報(bào)錯(cuò)檩互,因?yàn)闆]有輸入饿肺,自然也無法判斷輸出是啥類型了。
>>>type(max)
builtin_function_or_method
>>>type(max([1,2,3]))
int
>>>type(max([1.,2.,3.]))
float
>>>type(max())
TypeError: max expected 1 arguments, got 0
注意:
(1) 在利用type()查看函數(shù)或方法時(shí)盾似,函數(shù)名或方法名代表了函數(shù)或方法本身敬辣,而帶上'()'則表示返回值的類型,如前面的type(max)和type(max())零院。
(2) python的部分關(guān)鍵字溉跃,如and、as告抄、break撰茎、if、elif等等打洼,確實(shí)是沒有類型的龄糊,連‘NoneType’都不算。輸入type(and)募疮,將得到錯(cuò)誤信息SyntaxError: invalid syntax炫惩。可憐阿浓,這些關(guān)鍵字作用很大他嚷,連個(gè)對象都不算!
Python中盡量用狹義的“對象”概念進(jìn)行編程
雖然Python對“對象”是寬容的,但大部分對象依然具備狹義“對象”的基本特性,即:對象有“屬性attribute”和“方法method”筋蓖!換句話說卸耘,操作對象可以通過點(diǎn)操作符“.”進(jìn)行,即:
“object.attribute”或“object.method()”
還是舉實(shí)例來直觀說明粘咖。在MATLAB中對a=-1求絕對值必須用abs(a)的方式進(jìn)行蚣抗,因?yàn)閍不是一個(gè)狹義的對象,它本身沒有屬性和方法瓮下,因此只能通過第三方函數(shù)進(jìn)行操作翰铡。
在Python中情況就不一樣了,a=-1它不僅是一個(gè)int整數(shù)唱捣,它也是一個(gè)int類型的對象,有它自己的屬性和方法网梢,取絕對值操作震缭,不僅可以利用內(nèi)置函數(shù)abs(),同樣可以利用自身方法“__abs__()”战虏,看如下代碼拣宰,兩者結(jié)果是完全相同的。
>>>a = -1
>>>print(abs(a))
>>>print(a.__abs__())
1
1
Python中的對象千千萬烦感,想要記住每一個(gè)對象都有啥屬性和方法是不切實(shí)際的巡社。但Python有一個(gè)非常有用的函數(shù):dir(),它可以返回對象的基本屬性和方法手趣。如下所示晌该,三者都輸出了相同的結(jié)果,都是str對象的屬性和方法绿渣,可見dir()的參數(shù)可以是類名稱朝群、變量名、實(shí)際對象等中符。
>>>a = 'ABC'
>>>dir(str)
>>>dir(a)
>>>dir('ABC')
['__add__',
'__class__',
'__contains__',
'__delattr__',
'__dir__',
'__doc__',
'__eq__',
……]
體會(huì)面向?qū)ο蟛僮鞯镊攘Γ?/h4>
前面對比了“面向?qū)ο蟛僮鳌迸c“直接利用內(nèi)置函數(shù)操作”的差異姜胖,似乎沒展現(xiàn)出“面向?qū)ο蟆钡膬?yōu)點(diǎn)!別急淀散,下面的例子一定會(huì)讓你印象深刻右莱!將a=[1,2,[3,-4]]中的-4取絕對值并轉(zhuǎn)化為字符。
(1)利用第三方函數(shù)方法
str(abs(a[2][1]))
a[2]取出a的第三個(gè)元素[3,-4]档插;[1]表示取出[3,-4]中的第二元素-4慢蜓;abs()對-4取絕對值;str()將4轉(zhuǎn)化為字符郭膛。
>>>a=[1,2,[3,-4]]
>>>str(abs(a[2][1]))
'4'
(2)利用對象自身方法操作
a[2][1].__abs__().__str__()
首先a[2]取出[3,-4]胀瞪,是list對象;[1]取出-4,是int對象凄诞,它有一個(gè)__abs__()方法圆雁,返回絕對值4(依然是個(gè)int對象),int對象還有一個(gè)方法是__str__()帆谍,它將int轉(zhuǎn)化為str對象伪朽,得到字符‘4’。如果想對這個(gè)字符‘4’進(jìn)一步操作汛蝙,則可以利用dir(str)查看str都還有哪些方法烈涮,繼續(xù)加在后面便可。
>>>a=[1,2,[3,-4]]
>>>a[2][1].__abs__().__str__()
'4'
通過比較可知窖剑,利用函數(shù)方法會(huì)出現(xiàn)層層包含的括號坚洽,當(dāng)多個(gè)函數(shù)同時(shí)作用時(shí),顯得較為混亂西土。而利用“對象方法”則結(jié)構(gòu)清晰讶舰,各方法從左到右逐個(gè)執(zhí)行,由‘.’將各個(gè)方法分開需了,這種順序結(jié)構(gòu)一目了然跳昼。此外,內(nèi)置函數(shù)的數(shù)量是極有限的肋乍,通常是一些通用型函數(shù)鹅颊,對于很多特殊或者專門場景,無法在內(nèi)置函數(shù)中找到需要的函數(shù)墓造。通過將方法置于對象內(nèi)部堪伍,既方便使用,也避免了將很多極私有的方法暴露于外部環(huán)境中觅闽,引起結(jié)構(gòu)混亂杠娱。
鑒于Python的面向?qū)ο筇匦裕幊虝r(shí)應(yīng)利用對象的方法進(jìn)行操作谱煤!
注意:
在利用對象方法進(jìn)行操作時(shí)摊求,下一個(gè)方法能從哪些方法里面選,是由上一個(gè)方法的返回值類型決定的刘离,不能對int對象使用str對象的方法室叉。如下例,a[0]是一個(gè)int對象硫惕,有__abs__()方法茧痕,而a[1]是一個(gè)str對象,沒有__abs__()方法恼除,會(huì)報(bào)錯(cuò):
>>>a = [-1,'1']
>>>a[0].__abs__()
1
>>>a[1].__abs__()
AttributeError: 'str' object has no attribute
下面的例子中踪旷,__abs__()可以寫無限個(gè)曼氛,原因在于a是一個(gè)int對象,調(diào)用自身方法__abs__()后返回的還是int對象令野,因此可以無限寫下去舀患,雖然沒什么卵用,但有力展現(xiàn)了面向?qū)ο蠓椒ǖ奶攸c(diǎn)气破!
>>>a= -1
>>>a.__abs__().__abs__().__abs__().__abs__().__abs__()
1