9.3.4. 方法對象
目前成都創(chuàng)新互聯(lián)公司已為上千的企業(yè)提供了網(wǎng)站建設(shè)、域名、雅安服務(wù)器托管、網(wǎng)站托管、企業(yè)網(wǎng)站設(shè)計、洛江網(wǎng)站維護等服務(wù),公司將堅持客戶導(dǎo)向、應(yīng)用為本的策略,正道將秉承"和諧、參與、激情"的文化,與客戶和合作伙伴齊心協(xié)力一起成長,共同發(fā)展。
通常,方法通過右綁定方式調(diào)用:
x.f()
在 MyClass 示例中,這會返回字符串 'hello world'。然而,也不是一定要直接調(diào)用方法。 x.f 是一個方法對象,它可以存儲起來以后調(diào)用。例如:
xf = x.f
while True:
print(xf())
會不斷的打印 hello world。
調(diào)用方法時發(fā)生了什么?你可能注意到調(diào)用 x.f() 時沒有引用前面標(biāo)出的變量,盡管在 f() 的函數(shù)定義中指明了一個參數(shù)。這個參數(shù)怎么了?事實上如果函數(shù)調(diào)用中缺少參數(shù),Python 會拋出異常--甚至這個參數(shù)實際上沒什么用……
實際上,你可能已經(jīng)猜到了答案:方法的特別之處在于實例對象作為函數(shù)的第一個參數(shù)傳給了函數(shù)。在我們的例子中,調(diào)用 x.f() 相當(dāng)于 MyClass.f(x) 。通常,以 n 個參數(shù)的列表去調(diào)用一個方法就相當(dāng)于將方法的對象插入到參數(shù)列表的最前面后,以這個列表去調(diào)用相應(yīng)的函數(shù)。
如果你還是不理解方法的工作原理,了解一下它的實現(xiàn)也許有幫助。引用非數(shù)據(jù)屬性的實例屬性時,會搜索它的類。如果這個命名確認(rèn)為一個有效的函數(shù)對象類屬性,就會將實例對象和函數(shù)對象封裝進一個抽象對象:這就是方法對象。以一個參數(shù)列表調(diào)用方法對象時,它被重新拆封,用實例對象和原始的參數(shù)列表構(gòu)造一個新的參數(shù)列表,然后函數(shù)對象調(diào)用這個新的參數(shù)列表。
python的一切數(shù)據(jù)類型都是對象。但是python的對象分為不可變對象和可變對象。python的變量是引用,對python變量的賦值是引用去綁定該對象。
可變對象的數(shù)據(jù)發(fā)生改變,例如列表和字典,引用不會更改綁定對象,畢竟本身就是用于增刪改查的,頻繁地產(chǎn)生新對象必然導(dǎo)致開銷巨大,只需要該對象內(nèi)部變化就行;但對于綁定了不可變對象的引用,對象一旦改變就會使引用綁定新的對象。
這一點也會反應(yīng)到函數(shù)的參數(shù)上。python的傳值方式是“傳對象”引用。python的函數(shù),形參實際上是引用,實參便是對象綁定到該引用上。本質(zhì)是形參會被作為函數(shù)的局部變量,在開辟的函數(shù)的棧內(nèi)存中被聲明。
簡要來講:
如果參數(shù)是數(shù),則類似值傳遞,
如果參數(shù)是列表和字典,則類似引用傳遞。
每個對象都會有個id, 可以用id()驗證以上說法:
這個函數(shù)的參數(shù)是列表,是可變對象。
一、實例方法,類方法,靜態(tài)方法
我們首先寫一個類,里面包含這三種方法。
可以看到,我們用到了兩個裝飾器。
我們用類和實例分別調(diào)用下類方法
我們用類和實例分別調(diào)用下靜態(tài)方法
靜態(tài)方法其實就是把一個普通的函數(shù)寫在類里,與直接在外層寫一個函數(shù)是一樣的,本質(zhì)上是一個函數(shù)。
為了方便理解,我們分別打印下這些方法的類型
通過type()查看對象是方法還是函數(shù)
此外,還可以通過inspect模塊判斷某個對象是否是某種類型,返回布爾值。
用法
小Tips:概念理解
直接def定義的,我們叫做函數(shù)
把函數(shù)放到類里,我們叫做方法
方法可以通過裝飾器staticmethod轉(zhuǎn)為(放在方法里的)函數(shù)
繼承
一個類繼承另一個類時,會自動獲得另一個類的所有屬性和方法,被繼承的類稱之為父類,新類稱為子類。子類擁有父類所有的屬性和方法,并且可以定義自己的屬性和方法
我們以上邊的Rectangle類為父類來試一下
1)完全繼承
可以看到,子類完全繼承父類后,可以直接調(diào)用父類的所有方法。
2)部分繼承
部分繼承:繼承父類后,修改父類的同名方法
我們試一下,Square繼承Rectangle后,修改__init__()方法
3)拓展父類的方法
在保留父類中某個方法的代碼同時,對方法進行拓展
可以在方法中加入"super().方法名"來實現(xiàn)
4)@property
9.3.3. 實例對象
現(xiàn)在我們可以用實例對象作什么?實例對象唯一可用的操作就是屬性引用。有兩種有效的屬性名。
數(shù)據(jù)屬性 相當(dāng)于 Smalltalk 中的“實例變量”或 C++ 中的“數(shù)據(jù)成員”。和局部變量一樣,數(shù)據(jù)屬性不需要聲明,第一次使用時它們就會生成。例如,如果 x 是前面創(chuàng)建的 MyClass 實例,下面這段代碼會打印出 16 而在堆棧中留下多余的東西:
x.counter = 1
while x.counter 10:
x.counter = x.counter * 2
print(x.counter)
del x.counter
另一種為實例對象所接受的引用屬性是 方法。方法是“屬于”一個對象的函數(shù)。(在 Python 中,方法不止是類實例所獨有:其它類型的對象也可有方法。例如,鏈表對象有 append,insert,remove,sort 等等方法。然而,在后面的介紹中,除非特別說明,我們提到的方法特指類方法)
實例對象的有效名稱依賴于它的類。按照定義,類中所有(用戶定義)的函數(shù)對象對應(yīng)它的實例中的方法。所以在我們的例子中,x.f 是一個有效的方法引用,因為 MyClass.f 是一個函數(shù)。但 x.i 不是,因為 MyClass.i 不是函數(shù)。不過 x.f 和 MyClass.f 不同,它是一個 方法對象 ,不是一個函數(shù)對象。
python中,所有的元素都是對象,其中第一類對象的通用特性:可作為值傳遞,賦值給另一個對象;可以作為元素添加到集合對象中;可以作為參數(shù)傳遞給其他函數(shù);可以作為函數(shù)的返回值