python面向物件中類物件、例項物件、類變數、例項變數、類方法、例項方法、靜態方法
1. 類物件和例項物件
Python
中一切皆物件,Python類本身也是一種物件,類定義完成後,會在當前作用域中定義一個以類名為名字的名稱空間。類物件具有以下兩種操作:
- 可以通過“類名()”的方式例項化一個物件。
- 可以通過“類名.類屬性”的方式來訪問一個類屬性。
如果說類時一種概念性的定義,是一種類別,那麼例項物件就是對這一類別的具體化、例項化,即例項化物件是類物件例項化之後的產物。
class Person:# 宣告一個類物件 pass p1 = Person()#宣告一個例項物件 print(Person)#輸出結果:<class '__main__.Person'>print(p1)#<__main__.Person object at 0x0000015F7F94D0F0>
2 類變數與例項變數
2.1 概念上的區別
類變數是指是指該類的所有例項說共有的資料,例項變數是該類每一個例項所特有的資料。這麼說的話可能還是很抽象,我們拿人類(Person類)來打比方,人類能移動(move=True),這是每一個人(張三、李四)都能做的,所以我們可以說人類能移動,張三能移動,李四也能移動,這裡的移動(move)就是一個類變數。但每一個人都可能有不同的姓名(name)和年齡(age),張三可能20歲,李四可能30歲,但是我們不能說人類(Person)都是20歲或30歲,這裡的姓名(name)和年齡(age)就是例項變數。
class Person: move = True # 這是類變數 def __init__(self , name , age): self.name = name # 這是例項變數 self.age = age # 這是例項變數
2.2 宣告上的區別
類變數宣告通常在類內部,但函式體外,不需要用任何關鍵字修飾。例項變數一般宣告在例項方法內部(其他方法內部也不行),且用self關鍵字修飾。
class Person: move = True # 這是類變數, def __init__(self , name): self.name = name # 這是例項變數,必須宣告在例項函式內,用self關鍵字修飾 # move = True # 類變數不能再函式體內宣告,在這個位置宣告的又沒有self關鍵字修飾,只能是一個區域性變數 # self.age = age # 這是錯誤的,例項變數不能再這裡宣告 eat = True # 這是類變數,可以在函式體外,類內部任意位置
上面的變數繫結都是在物件宣告過程中繫結的,但事實上類變數和例項變數都可以在類或者例項都可以在物件宣告結束之後再繫結。“類名.變數名”繫結的是類變數,“例項名.變數名”繫結的是例項變數。
class Person: move = True def __init__(self , name , age): self.name = name self.age = age p1 = Person('張三' , 20) p1.gender='男' # 宣告例項物件結束之後再繫結一個例項變數 Person.eat = True # 宣告類物件結束之後再繫結一個類變數 print(p1.gender) # 輸出結果:男 print(p1.eat) #輸出結果:True
注:雖然可以在物件宣告之後再繫結物件,但是這種方式最好不要使用。
2.3 訪問上的區別
類變數可以通過“類名.變數名”和“例項名.變數名”的方式訪問。例項變數只能通過“例項名.變數名”的方式來訪問。
class Person: move = True # 這是類變數 def __init__(self , name , age): self.name = name # 這是例項變數 self.age = age # 這是例項變數 p1 = Person('張三' , 20) print(p1.name , p1.age) # 通過“例項名.變數名”的方式訪問例項變數 print(p1.move) # 通過“例項名.變數名”的方式訪問例項變數 print(Person.move) # 通過“類名.變數名”方式訪問類變數 # print(Person.name) # 這是錯誤的
注:雖然可以通過“例項名.類變數名”的方式訪問類變數,但是並不推薦,最好還是通過“類名.類變數名”來訪問類變數。
2.4 儲存上的區別
類變數只會在用class關鍵字宣告一個類時建立,且也只會儲存在類的名稱空間中,這個類的例項的名稱空間中是沒有的。通過“例項名.類變數名”訪問類變數時,實際訪問的是類名稱空間中資料,所以所有例項訪問到的資料都是同一個變數。例項變數儲存在例項各自的名稱空間中。
class Person: move = True # 這是類變數 def __init__(self , name , age): self.name = name # 這是例項變數 self.age = age # 這是例項變數 p1 = Person('張三' , 20) p2 = Person('李四' , 30) # 通過id()函式查詢move記憶體地址 print(id(p1.move)) # 輸出結果為:1622667424 print(id(p1.move)) # 輸出結果為:1622667424
3 靜態方法、類方法、例項方法
3.1 靜態方法
靜態方法是指在定義時,使用@staticmethod裝飾器來修飾,無序傳入self或cls關鍵字即可進行建立的方法。在呼叫過程時,無需將類例項化,直接通過“類名.方法名()”方式呼叫方法。當然,也可以在例項化後通過“例項名.方法名()”的方式呼叫。在靜態方法內部,只能通過“類名.類變數名”的方式訪問類變數。
class Person: move = True def __init__(self , name , age): self.name = name self.age = age @staticmethod def static_fun(): # 宣告一個靜態方法 print(Person.move) p1 = Person('張三' , 20) p1.static_fun() #輸出結果:這是靜態方法 Person.static_fun() #輸出結果:這是靜態方法
3.2 類方法
類方法需要使用@classmethod裝飾器來修飾,且傳入的第一個引數為cls,指代的是類本身。類方法在呼叫方式上與靜態方法相似,即可以通過“類名.方法名()”和“例項名.方法名()”兩種方式呼叫。但類方法與靜態方法不同的是,類方法可以在方法內部通過cls關鍵字訪問類變數。在類方法內部,既能通過“類名.類變數名”的方式訪問類變數,也能通過“cls.類變數名”的方式訪問類變數。
class Person: move = True def __init__(self , name , age): self.name = name self.age = age @classmethod def class_fun(cls): # 宣告一個類方法 print(cls.move) print(Person.move)# cls 指的就是Person類,等效 p1 = Person('張三' , 20) p1.class_fun() #輸出結果:True True Person.class_fun() #輸出結果:True True
3.3 例項方法
在一個類中,除了靜態方法和類方法之外,就是例項方法了,例項方法不需要裝飾器修飾,不過在宣告時傳入的第一個引數必須為self,self指代的就是例項本身。例項方法能訪問例項變數,靜態方法和類方法則不能。在例項方法內部只能通過“類名.類變數名”的方式訪問類變數。在呼叫時,例項方法可以通過“例項名.例項方法名”來呼叫,如果要通過類來呼叫,必須必須顯式地將例項當做引數傳入。
class Person: move = True def __init__(self , name , age): self.name = name self.age = age def instance_fun(self): # 宣告一個例項方法 print(Person.move) # 訪問類變數 print(self.name , self.age) p1 = Person('張三' , 20) p1.instance_fun() Person.instance_fun(p1) #通過類訪問例項方法時,必須顯式地將例項當做引數傳入