Python中的類方法、實例方法、靜態方法、構造方法
python基礎知識回顧
- 類(Class): 用來描述具有相同的屬性和方法的對象的集合。它定義了該集合中每個對象所共有的屬性和方法。對象是類的實例。
- 方法:類中定義的函數。
- 類變量:類變量在整個實例化的對象中是公用的。類變量定義在類中且在函數體之外。類變量通常不作為實例變量使用。
- 數據成員:類變量或者實例變量用於處理類及其實例對象的相關的數據。
- 方法重寫:如果從父類繼承的方法不能滿足子類的需求,可以對其進行改寫,這個過程叫方法的覆蓋(override),也稱為方法的重寫。
- 局部變量:定義在方法中的變量,只作用於當前實例的類。
- 實例變量:在類的聲明中,屬性是用變量來表示的。這種變量就稱為實例變量,是在類聲明的內部但是在類的其他成員方法之外聲明的。
- 繼承:即一個派生類(derived class)繼承基類(base class)的字段和方法。繼承也允許把一個派生類的對象作為一個基類對象對待。例如,有這樣一個設計:一個Dog類型的對象派生自Animal類,這是模擬"是一個(is-a)"關系(例如,Dog是一個Animal)。
- 實例化:創建一個類的實例,類的具體對象。
- 對象:通過類定義的數據結構實例。對象包括兩個數據成員(類變量和實例變量)和方法。
\(~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\)
類實例化后,可以使用其屬性,實際上,創建一個類之后,可以通過類名訪問其屬性。
類對象支持兩種操作:屬性引用和實例化。
1.屬性引用使用和 Python 中所有的屬性引用一樣的標准語法:obj.name。
2.類對象創建后,類命名空間中所有的命名都是有效屬性名。
類有一個名為 init() 的特殊方法(構造方法),該方法在類實例化時會自動調用,也就是說,我們在實例化對象時,這個方法就是用來初始化實例對象的屬性的。
當然, init() 方法可以有參數,參數通過 init() 傳遞到類的實例化操作上。例如:
class Computer:
def __init__(self, cpu, hd):
self.cpu = cpu
self.hd = hd
c1 = Computer('i7','512')
print(c1.cpu, c1.hd) # 輸出結果:i7 512
\(~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\)
self代表類的實例,而非類
類的方法與普通的函數只有一個特別的區別——它們必須有一個額外的第一個參數名稱, 按照慣例它的名稱是 self。(也就是說,用其他名稱也可以,但通常我們寫成self)
class Test:
def prt(self):
print(self)
print(self.__class__)
t = Test()
t.prt()
#運行結果
<__main__.Test object at 0x000002CA3CA28748>
<class '__main__.Test'>
從執行結果可以很明顯的看出,self 代表的是類的實例,代表當前對象的地址,而 self.class 則指向類。
self 不是 python 關鍵字,我們把他換成 其他名稱也是可以正常執行的。
\(~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\)
類的方法
在類的內部,使用 def 關鍵字來定義一個方法,與一般函數定義不同,類方法必須包含參數 self, 且為第一個參數,self 代表的是類的實例。
#類定義
class people:
#定義基本屬性
name = ''
age = 0
#定義私有屬性,私有屬性在類外部無法直接進行訪問
__weight = 0
#定義構造方法
def __init__(self,n,a,w):
self.name = n
self.age = a
self.__weight = w
def speak(self):
print("%s 說: 我 %d 歲了" %(self.name,self.age))
# 實例化類
p = people('jack',10,120)
p.speak()
#運行結果
jack 說: 我 10 歲了
\(~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\)
類的私有屬性
__private_attrs:兩個下划線開頭,聲明該屬性為私有,不能在類的外部被使用或直接訪問。在類內部的方法中使用時 self.__private_attrs。
\(~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\)
類的私有方法
__private_method:兩個下划線開頭,聲明該方法為私有方法,只能在類的內部調用 ,不能在類的外部調用。self.__private_methods。
類的專有方法
init : 構造函數,在生成對象時調用
del : 析構函數,釋放對象時使用
repr : 打印,轉換
setitem : 按照索引賦值
getitem: 按照索引獲取值
len: 獲得長度
cmp: 比較運算
call: 函數調用
add: 加運算
sub: 減運算
mul: 乘運算
truediv: 除運算
mod: 求余運算
pow: 乘方
實例方法只能被實例對象調用,靜態方法(由@staticmethod裝飾的方法)、類方法(由@classmethod裝飾的方法),可以被類或類的實例對象調用。
總結:
1.實例方法:第一個參數必須要默認傳實例對象,一般習慣用self。
通過self引用的可能是類屬性、也有可能是實例屬性(這個需要具體分析),不過在存在相同名稱的類屬性和實例屬性的情況下,實例屬性優先級更高
2.靜態方法:修飾器@staticmethod來標識其為靜態方法
靜態方法中引用類屬性的話,必須通過類對象來引用,不能訪問實例屬性
3.類方法:修飾器@classmethod來標識其為類方法
第一個參數必須要默認傳類,一般習慣用cls(表示類本身)。
類方法是只與類本身有關而與實例無關的方法。
通過cls引用的必定是類對象的屬性和方法,不能訪問實例屬性
能夠通過實例對象和類對象去訪問類方法
@staticmethod和@classmethod都可以直接類名.方法名()來調用,那他們有什么區別呢
從它們的使用上來看,
@staticmethod不需要表示自身對象的self和自身類的cls參數,就跟使用函數一樣。
@classmethod也不需要self參數,但第一個參數需要是表示自身類的cls參數。
如果在@staticmethod中要調用到這個類的一些屬性方法,只能直接類名.屬性名或類名.方法名。
而@classmethod因為持有cls參數,可以來調用類的屬性,類的方法,實例化對象等,避免硬編碼。
方法(method)與函數(function)的區別:
1、方法用於類,且包含在類里(靜態方法可以寫在外面,但一般不這么做,靜態方法本可以理解為函數),方法是特殊的函數。
2、具體可以用type()來區分
3、區別方法和函數最本質的辦法還是看是否綁定類或實例,比如實例方法如果用類調用就會成為函數,用實例調用就是方法,而靜態方法沒有綁定任何類或實例,自然就是函數
4、*裝飾器不會改變被裝飾對象的類型
靜態方法與普通方法區別
- 靜態的內存空間是固定的,相對來說更省資源。創實例的創一個實例就要開辟一個新內存,耗費資源
- 靜態方法屬於類所有,類實例化前即可使用;
- 非靜態方法可以訪問類中的任何成員,靜態方法只能訪問類中的靜態成員;
- 因為靜態方法在類實例化前就可以使用,而類中的非靜態變量必須在實例化之后才能分配內存;
- static內部只能出現static變量和其他static方法!而且static方法中還不能使用this等關鍵字,因為它是屬於整個類;
- 靜態方法效率上要比實例化高,靜態方法的缺點是不自動進行銷毀,而實例化的則可以做銷毀;
- 靜態方法和靜態變量創建后始終使用同一塊內存,而使用實例的方式會創建多個內存。
主要區別:靜態方法在創建對象前就可以使用了,非靜態方法必須通過new出來的對象調用。 - 靜態方法可以通過 類名::方法名直接調用。普通方法需要創建一個實例,也就是new一個對象,然后通過 對象名->方法名的方式來調用
- 靜態類只能包含靜態成員,否則會拋出編譯錯誤;然而非靜態類既可以包含非靜態成員也可以包含靜態成員
- 靜態類是不能實例化,之所以不能實例化,是因為靜態類會導致C#編譯器將該類同時標記為abstract和sealed,並且編譯器不會在類型中
- 生成一個實例的構造函數,從而導致靜態類不能實例化;非靜態類可以,並且靜態成員的訪問只能通過類來進行訪問,因為靜態成員是屬於類的。