類成員 | 註釋 |
---|---|
欄位 | - |
靜態欄位 | 每個物件資料相同 |
普通欄位 | 每個物件資料不同 |
方法 | - |
靜態方法 | @staticmethod,只能使用類來呼叫,無需例項化物件 |
類方法 | @classmethod,被呼叫時會自動傳入“類名”引數 |
普通方法 | 使用物件中的資料 |
屬性 | - |
普通屬性 | 用於將方法偽造成欄位 |
一般來說,有self就通過物件呼叫,無self就通過類來呼叫
一、欄位
- 普通欄位,屬於物件,普通欄位在每個物件中都要儲存一份。
- 靜態欄位,屬於類,在記憶體中只儲存一份。
class Provice:
country = "China" # 靜態欄位,建議使用類來呼叫
def __init__(self, name):
temp = "xxx"
self.name = name # 普通欄位,存在物件中
def show(self):
print('show') # 普通方法,存在類中
hebei = Provice("河北")
henan = Provice("河南")
print(hebei.country) #China
二、方法
- 普通方法,存在類中,建議使用物件呼叫。
- 靜態方法,沒有self,使用類來呼叫,無需例項化物件。
- 類方法,建議使用類呼叫,類方法在被呼叫時會自動在它的引數中傳入類名(Provice)。
注:所有的方法,均屬於類(非物件)中,所以,在記憶體中也只儲存一份。
# 物件類成員
class Provice:
country = "China"
def __init__(self, name):
self.name = name
def show(self): #普通方法
print('show')
@staticmethod
def xo(): #靜態方法
print('xo')
@classmethod #類方法
def xxoo(cls):
print('xxoo',cls)
hebei = Provice("河北")
print(Provice.country) # China
Provice.xo()
Provice.xxoo()
三、屬性
可以把方法偽造成欄位,普通欄位通過“物件.欄位”來獲取,可以修改欄位的值。那麼屬性同樣可以獲取和修改,只是實現方法不太一樣。
屬性的定義和呼叫要注意一下幾點:
- 定義時,在普通方法的基礎上新增 @property 裝飾器;
- 定義時,屬性僅有一個self引數
- 呼叫時,無需括號:
(a)方法:foo_obj.func()
(b)屬性:foo_obj.prop
(1) 裝飾器方式定義屬性
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.deltter
def price(self, value):
del self.original_price
obj = Goods()
obj.price # 獲取商品價格
obj.price = 200 # 修改商品原價
del obj.price # 刪除商品原價
(2) 使用靜態欄位的方式建立屬性
property的構造方法中有個四個引數:
第一個引數是方法名,呼叫“物件.屬性”時自動觸發執行方法
第二個引數是方法名,呼叫“物件.屬性 = XXX”時自動觸發執行方法
第三個引數是方法名,呼叫“del 物件.屬性”時自動觸發執行方法
第四個引數是字串,呼叫”物件.屬性.__doc__” ,此引數是該屬性的描述資訊
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 # 獲取商品價格,自動呼叫get_price方法
obj.PRICE = 200 # 修改商品原價,自動呼叫set_price方法
del obj.PRICE # 刪除商品原價,自動呼叫del_price方法
四、成員修飾符
對於每一個類的成員而言都有兩種形式:
- 公有成員,在任何地方都能訪問
- 私有成員,只有在類的內部才能方法(但是可以間接呼叫)
預設情況下,python類的成員屬性與方法都是“public”。python的“訪問控制符”可以限定成員函式的訪問。
- 雙下劃線(__),在類裡可見。
- 單下劃線(_),在模組內可見。還可以防止模組的屬性用“from mymodule import *”來載入
class C:
def __init__(self):
self.name = '公有欄位'
self.__foo = "私有欄位"
私有靜態欄位:
class C:
__name = "私有靜態欄位"
def func(self):
print C.__name
class D(C):
def show(self):
print C.__name
C.__name # 類訪問 ==> 錯誤
obj = C()
obj.func() # 類內部可以訪問 ==> 正確
obj_son = D()
obj_son.show() # 派生類中可以訪問 ==> 錯誤
五、類的特殊成員
(1) __doc__
class Foo:
""" 描述類資訊,這是用於看片的神奇 """
def func(self):
pass
print Foo.__doc__
#輸出:類的描述資訊
(2) __module__ 和 __class__
__module__表示當前操作的物件在那個模組
__class__表示當前操作的物件的類是 什麼
#lib/aa.py
class C:
def __init__(self):
self.name = 'morra'
#test.py
from lib.aa import C
obj = C()
print obj.__module__ #lib.aa,即:輸出模組
print obj.__class__ #lib.aa.C,即:輸出類
(3) __init__
構造方法,通過類建立物件時,自動觸發執行。
class Foo:
def __init__(self, name):
self.name = name
self.age = 18
obj = Foo('wupeiqi') # 自動執行類中的 __init__ 方法
(4) __del__
析構方法,當物件在記憶體中被釋放時,自動觸發執行。
注:此方法一般無須定義,因為Python是一門高階語言,程式設計師在使用時無需關心記憶體的分配和釋放,因為此工作都是交給Python直譯器來執行,所以,解構函式的呼叫是由直譯器在進行垃圾回收時自動觸發執行的。
class Foo:
def __del__(self):
pass
(5) __call__
物件後面加括號,觸發執行。
注:構造方法的執行是由建立物件觸發的,即:物件 = 類名() ;而對於 call 方法的執行是由物件後加括號觸發的,即:物件() 或者 類()()
class Foo:
def __init__(self):
pass
def __call__(self, *args, **kwargs):
print '__call__'
obj = Foo() # 執行 __init__
obj() # 執行 __call__
(6) __dict__
獲取類或物件中的所有成員,在自定義form框架的時候用的比較多。
class Foo:
"""我是類的註釋"""
def __init__(self):
self.name = 'morra'
obj = Foo()
print(obj.__dict__) #{'name': 'morra'},
for k,v in Foo.__dict__.items():
print(k,v)
#------------
#__doc__ 我是類的註釋
#__init__ <function Foo.__init__ at 0x10197ba60>
#__dict__ <attribute '__dict__' of 'Foo' objects>
#__module__ __main__
#__#weakref__ <attribute '__weakref__' of 'Foo' objects>
(7) __str__
如果一個類中定義了__str__方法,那麼在列印 物件 時,預設輸出該方法的返回值。
class Foo:
def __init__(self,name):
self.name= name
def __str__(self):
return "我是物件的輸出結果"
obj = Foo('morra')
print(obj) #執行print(obj)或者str(obj)的時候,會自動執行__str__
(8) __getitem__、__setitem__、__delitem__
class Foo:
def __init__(self):
print('init')
def __getitem__(self, item):
print(item)
def __setitem__(self, key, value):
print(key,value)
def __delitem__(self, key):
print(key)
r['xx'] #物件後加[]會直接執行__getitem__
r['xxx']=123 #自動執行__setitem__
del r['aaaa'] #自動執行__delitem__
r[1:3] #做切片操作的時候還是會執行__getitem__方法,python會自動把1:3封裝成一個物件傳入__getitem__
r[1:3]=123 #執行__setitem__
del[1:3]=456 #執行__delitem__
(9) __iter__
class Foo:
def __init__(self):
self.name = 'morra'
def __iter__(self):
yield 1
yield 2
yield 3
obj = Foo()
for i in obj: # 執行for迴圈的時候,會自動執行物件的__iter__方法
print(i)
(10) __metaclass__
class Foo(object):
def __init__(self):
pass
obj = Foo() # obj是通過Foo類例項化的物件
上述程式碼中,obj 是通過 Foo 類例項化的物件,其實,不僅 obj 是一個物件,Foo類本身也是一個物件,因為在Python中一切事物都是物件。
如果按照一切事物都是物件的理論:obj物件是通過執行Foo類的構造方法建立,那麼Foo類物件應該也是通過執行某個類的 構造方法 建立。
print type(obj) # 輸出:<class '__main__.Foo'> 表示,obj 物件由Foo類建立
print type(Foo) # 輸出:<type 'type'> 表示,Foo類物件由 type 類建立
所以,obj物件是Foo類的一個例項,Foo類物件是 type 類的一個例項,即:Foo類物件 是通過type類的構造方法建立。
那麼,建立類就可以有兩種方式:
(a). 普通方式
class Foo(object):
def func(self):
print 'hello wupeiqi'
(b).特殊方式(type類的建構函式)
def func(self):
print 'hello wupeiqi'
Foo = type('Foo',(object,), {'func': func})
#type第一個引數:類名
#type第二個引數:當前類的基類
#type第三個引數:類的成員
類是由type類例項化產生的。
那麼問題來了,類預設是由type類例項化產生,type類中如何實現的建立類?類又是如何建立物件?
答:類中有一個屬性__metaclass__,其用來表示該類由誰來例項化建立,所以,我們可以為__metaclass__設定一個type類的派生類,從而檢視類建立的過程。