類,也許是從計算機的角度去結構這個世界的唯一方式。本文是一篇入門級別的文章,是有關於Python類的基礎語法特性。主要內容有:類的方法(即C/C++中的函數),類的屬性(即成員變量)。
寫在前面:
本文是一篇學習筆記、有一定的總結性的文章,可能只適合有相關基礎的人作爲複習和查漏補缺。也許不適合新手!
類的定義
以Student類爲例,在Python中,定義類是通過class關鍵字:
class Student(object):
pass
解釋:
- class後面緊接着是類名,即Student,
- 類名通常是大寫開頭的單詞,緊接着是(object),表示該類是從哪個類繼承下來的,繼承的概念我們後面再講,
- 通常,如果沒有合適的繼承類,就使用object類,這是所有類最終都會繼承的類。
類方法
類方法包括:普通方法、靜態方法和類方法,三種方法在內存中都歸屬於類,區別在於調用方式不同。
三種類的方法
- 普通方法:由
對象
調用;至少一個self
參數;執行普通方法時,自動將調用該方法的對象
賦值給self
; - 類方法:由
類
調用; 至少一個cls
參數;執行類方法時,自動將調用該方法的類複製給cls; - 靜態方法:由
類
調用;無默認參數;
三種類方法的調用:
class Foo:
def __init__(self, name):
self.name = name
def ord_func(self): # 定義普通方法,至少有一個self參數
print('普通方法')
@classmethod # 定義類方法,至少有一個cls參數
def class_func(cls):
print('類方法')
@staticmethod # 定義靜態方法 ,無默認參數
def static_func():
print('靜態方法')
# 調用普通方法
f = Foo()
f.ord_func()
# 調用類方法
Foo.class_func()
# 調用靜態方法
Foo.static_func()
三種方法的區別:
- 相同點:對於所有的方法而言,均屬於類(非對象)中,所以,在內存中也只保存一份。
- 不同點:方法調用者不同、調用方法時自動傳入的參數不同。
特殊的內置方法
__init__
構造函數,在生成對象時調用__del__
析構函數,釋放對象時使用__str__
顯示該類的實例的信息,類似於Java中Object類的toString方法- …
爲了不喧賓奪主,這裏這是簡單介紹一下內置方法,更加詳細的內置方法,後文將更加詳細地介紹!
init內置方法
__init__()
:
- 類似於Java中的帶參構造方法,特殊方法“init”前後分別有兩個下劃線!!!
- 第一個參數永遠是self,表示創建的實例本身,因此,在__init__方法內部,就可以把各種屬性綁定到self,因爲self就指向創建的實例本身。
- self類似於Java中的this指針;
class Student(object): # 定義類
def __init__(self, name, score): # 定義構造方法
self.name = name
self.score = score
del內置方法
__del__()
:
理解del內置方法:
- 與 init() 方法對應的是
__del__
() 方法,__init__
() 方法用於初始化 Python 對象, - 而
__del__
() 則用於銷燬 Python 對象, - 即在任何 Python 對象將要被系統回收之時,系統都會自動調用該對象的
__del__
() 方法。
當程序不再需要一個 Python 對象時,系統必須把該對象所佔用的內存空間釋放出來,這個過程被稱爲垃圾回收(GC,Garbage Collector),Python 會自動回收所有對象所佔用的內存空間,因此開發者無須關心對象垃圾回收的過程。
**注意:**對一個變量執行 del 操作,該變量所引用的對象就會被回收,只有當對象的引用計數變成 0 時,該對象纔會被回收。因此,如果一個對象有多個變量引用它,那麼 del 其中一個變量是不會回收該對象的。
class Item:
def __init__(self, name, price):
self.name = name
self.price = price
def __del__ (self): # 定義析構函數
print('del刪除對象')
im = Item('鼠標', 29.8) # 創建一個Item對象,將之賦給im變量
x = im # 打印im所引用的Item對象
del im
print('--這是最後一句Python語句--') # 只有執行最後一句,該類的對象不再被使用,才del
'''輸出:
--這是最後一句Python語句--
del刪除對象
'''
str內置方法
__str__()
:
類似於Java中的“toString”方法;用於輸出本類的信息;
class Student(object):
def __init__(self, name):
self.name = name
def __str__(self):
return 'Student object (name: %s)' % self.name
print(Student('Michael')) # 輸出:Student object (name: Michael)
# 如果不定義"__str__",輸出:<__main__.Student object at 0x109afb190>
類屬性
屬性的定義有兩種方式:
- 裝飾器,即:在方法上應用裝飾器
- 靜態字段,即:在類中定義值爲property對象的靜態字段
在哪裏定義類屬性:
1、直接在類中定義屬性
class UserInfo(object):
name = '兩點水'
2、在構造函數中定義屬性
class UserInfo(object):
def __init__(self, name):
self.name = name
類變量的定義方式:
xx
:公有變量_xx
:單前置下劃線,受保護的屬性或方法(相當於protected),類對象和子類可以訪問,from somemodule import *禁止導入__xx
:雙前置下劃線,私有化屬性或方法(相當於private),無法在外部直接訪問(名字重整所以訪問不到),訪問這種變量只能通過getter和setter函數來實現。__xx__
:雙前後下劃線,系統定義名字(不要自己發明這樣的名字)xx_
:單後置下劃線,用於避免與Python關鍵詞的衝突
靜態變量
有兩種方式:
- 普通方式
- property方式
普通靜態變量
class Province:
country = '中國' # 類的靜態變量,類似於Java中的static
def __init__(self, name):
self.name = name # 普通(對象)的屬性
obj = Province('河北省') # 直接訪問普通屬性
print(obj.name)
print(Province.country) # 直接訪問靜態變量
• 靜態變量在內存中只保存一份
• 普通變量在每個對象中都要保存一份
應用場景: 通過類創建對象時,如果每個對象都具有相同的字段,那麼就使用靜態字段
property的靜態變量
快速理解property方法:
class Foo:
def get_bar(self):
return 'constant info'
BAR = property(get_bar) # 創建常量"BAR",把get_bar方法的返回值賦值給它;
obj = Foo()
reuslt = obj.BAR # 自動調用get_bar方法,並獲取方法的返回值
print(reuslt)
property的構造方法中有個四個參數:
- 第一個參數是方法名,調用 對象.屬性 時自動觸發執行方法
- 第二個參數是方法名,調用 對象.屬性 = XXX 時自動觸發執行方法
- 第三個參數是方法名,調用 del 對象.屬性 時自動觸發執行方法
- 第四個參數是字符串,調用 對象.屬性.doc ,此參數是該屬性的描述信息
class Foo:
def get_bar(self):
return 'wupeiqi'
def set_bar(self, value): # *必須兩個參數
return
return 'set value' + value
def del_bar(self):
return 'wupeiqi'
BAR = property(get_bar, set_bar, del_bar, 'description...') # 定義一個BAR常量
obj = Foo()
obj.BAR # 自動調用第一個參數中定義的方法:get_bar
obj.BAR = "alex" # 自動調用第二個參數中定義的方法:set_bar方法,並將“alex”當作參數傳入
del Foo.BAR # 自動調用第三個參數中定義的方法:del_bar方法
obj.BAE.__doc__ # 自動獲取第四個參數中設置的值:description...
操作靜態字段
- 由於靜態字段方式創建屬性具有三種訪問方式,我們可以根據他們幾個屬性的訪問特點,分別將三個方法定義爲對同一個屬性:獲取、修改、刪除
class Goods(object):
def __init__(self):
self.original_price = 100 # 原價
self.discount = 0.8 # 折扣
def get_price(self):
new_price = self.original_price * self.discount # 實際價格 = 原價 * 折扣
return new_price
def set_price(self, value):
self.original_price = value
def del_price(self, value):
del self.original_price
PRICE = property(get_price, set_price, del_price, '價格屬性描述...')
obj = Goods()
obj.PRICE # 獲取商品價格
print('現在商品的價格是:',obj.PRICE)
obj.PRICE = 200 # 修改商品原價
print('修改後商品的價格是:',obj.PRICE)
#del obj.PRICE # 刪除商品原價
裝飾器
如果你已經瞭解Python類中的方法,那麼屬性就非常簡單了,因爲Python中的屬性其實是普通方法的變種。即,通過“@property”裝飾器,將一個方法變成一個變量或常量。
裝飾器的類變量
class Goods:
@property
def price(self):
return 'hahha'
obj = Goods()
result = obj.price # 完全把price()方法,搞成了一個變量;如果result = obj.price() 錯誤!
print(result) # 輸出:hahha
# print(obj.price()) # 報錯:TypeError: 'str' object is not callable
屬性的定義和調用要注意一下幾點:
• 定義時,在普通方法的基礎上添加 @property 裝飾器;
• 定義時,屬性僅有一個self參數
• 調用時,無需括號,即被@property裝飾的方法不再是一個方法,而是一個類屬性(類變量);
注意: 屬性存在意義是:訪問屬性時可以製造出和訪問字段(類變量)完全相同的假象
屬性由方法變種而來,如果Python中沒有屬性,方法完全可以代替其功能。
裝飾器與經典類、新式類
經典類(類名後的括號裏沒繼承“object”):
# ############### 定義 ###############
class Goods:
@property
def price(self):
return "wupeiqi"
# ############### 調用 ###############
obj = Goods()
result = obj.price # 使得price方法變成一個變量,並獲取方法的返回值
print(result)
新式類(類名後的括號裏有“object”):具有三種@property裝飾器
# ############### 定義 ###############
# 新式類中的屬性有三種訪問方式,並分別對應了三個被@property、@方法名.setter、@方法名.deleter修飾的方法
class Goods(object):
@property
def price(self):
print('@property')
@price.setter
def price(self, value):
print('@price.setter')
@price.deleter
def price(self):
print('@price.deleter')
# ############### 調用 ###############
obj = Goods()
obj.price # 自動執行 @property 修飾的 price 方法,並獲取方法的返回值
obj.price = 123 # 自動執行 @price.setter 修飾的 price 方法,並將 123 賦值給方法的參數
del obj.price # 自動執行 @price.deleter 修飾的 price 方法
核心點:
- 經典類中的屬性只有一種訪問方式,其對應被 @property 修飾的方法
- 新式類中的屬性有三種訪問方式,並分別對應了三個被@property、@方法名.setter、@方法名.deleter修飾的方法
新式類的三個裝飾
class Goods(object):
def __init__(self):
self.original_price = 100 # 原價
self.discount = 0.8 # 折扣
@property
def price(self):
new_price = self.original_price * self.discount # 實際價格 = 原價 * 折扣
return new_price
@price.setter
def price(self, value):
self.original_price = value
@price.deleter
def price(self):
del self.original_price
obj = Goods()
obj.price # 獲取商品價格
print('原商品價格:',obj.price) # 輸出:原商品價格: 80.0
obj.price = 200 # 修改商品原價
print('修改後商品價格:',obj.price) # 輸出:修改後商品價格: 160.0
del obj.price # 刪除商品原價
內置變量:name
在有些Python文件中,在最後一行常見這樣的代碼:
這到底是什麼意思呢?
-
__name__
是一個變量。前後加了雙下劃線是因爲這是系統定義的名字。普通變量不要使用此方式命名變量。 -
Python有很多模塊,而這些模塊是可以獨立運行的!這點不像C++和C的頭文件。
-
import的時候是要執行所import的模塊的。
-
__name__
就是標識模塊的名字的一個系統變量。這裏分兩種情況:假如當前模塊是主模塊(也就是調用其他模塊的模塊),那麼此模塊名字就是__main__
,通過if判斷這樣就可以執行“__mian__
:”後面的主函數內容;假如此模塊是被import的,則此模塊名字爲文件名字(不加後面的.py),通過if判斷這樣就會跳過“__mian__
:”後面的內容。
通過上面方式,python就可以分清楚哪些是主函數,進入主函數執行;並且可以調用其他模塊的各個函數等等。
- 如果模塊是被導入,
__name__
的值爲模塊名字 - 如果模塊是被直接執行,
__name__
的值爲’__main__
’