物件導向類成員

morra發表於2016-11-07
類成員 註釋
欄位 -
靜態欄位 每個物件資料相同
普通欄位 每個物件資料不同
方法 -
靜態方法 @staticmethod,只能使用類來呼叫,無需例項化物件
類方法 @classmethod,被呼叫時會自動傳入“類名”引數
普通方法 使用物件中的資料
屬性 -
普通屬性 用於將方法偽造成欄位

一般來說,有self就通過物件呼叫,無self就通過類來呼叫

一、欄位

  1. 普通欄位,屬於物件,普通欄位在每個物件中都要儲存一份。
  2. 靜態欄位,屬於類,在記憶體中只儲存一份。
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

二、方法

  1. 普通方法,存在類中,建議使用物件呼叫。
  2. 靜態方法,沒有self,使用類來呼叫,無需例項化物件。
  3. 類方法,建議使用類呼叫,類方法在被呼叫時會自動在它的引數中傳入類名(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()

三、屬性

可以把方法偽造成欄位,普通欄位通過“物件.欄位”來獲取,可以修改欄位的值。那麼屬性同樣可以獲取和修改,只是實現方法不太一樣。

屬性的定義和呼叫要注意一下幾點:

  1. 定義時,在普通方法的基礎上新增 @property 裝飾器;
  2. 定義時,屬性僅有一個self引數
  3. 呼叫時,無需括號:
    (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類的派生類,從而檢視類建立的過程。

物件導向類成員

相關文章