一. 細分類的組成成員
之前咱們講過類大致分兩塊區域,如下圖所示:
每個區域詳細划分又可以分為:
class A: company_name = '老男孩教育' # 靜態變量(靜態字段) __iphone = '1353333xxxx' # 私有靜態變量(私有靜態字段) def __init__(self,name,age): #特殊方法 self.name = name #對象屬性(普通字段) self.__age = age # 私有對象屬性(私有普通字段) def func1(self): # 普通方法 pass def __func(self): #私有方法 print(666) @classmethod # 類方法 def class_func(cls): """ 定義類方法,至少有一個cls參數 """ print('類方法') @staticmethod #靜態方法 def static_func(): """ 定義靜態方法 ,無默認參數""" print('靜態方法') @property # 屬性 def prop(self): pass
二. 類的私有成員
對於每一個類的成員而言都有兩種形式:
- 公有成員,在任何地方都能訪問
- 私有成員,只有在類的內部才能方法
私有成員和公有成員的訪問限制不同:
靜態字段(靜態屬性)
- 公有靜態字段:類可以訪問;類內部可以訪問;派生類中可以訪問
- 私有靜態字段:僅類內部可以訪問;

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() # 派生類中可以訪問 公有靜態字段

class C: __name = "私有靜態字段" def func(self): print C.__name class D(C): def show(self): print C.__name C.__name # 不可在外部訪問 obj = C() obj.__name # 不可在外部訪問 obj.func() # 類內部可以訪問 obj_son = D() obj_son.show() #不可在派生類中可以訪問 私有靜態字段
普通字段(對象屬性)
- 公有普通字段:對象可以訪問;類內部可以訪問;派生類中可以訪問
- 私有普通字段:僅類內部可以訪問;

class C: def __init__(self): self.foo = "公有字段" def func(self): print self.foo # 類內部訪問 class D(C): def show(self): print self.foo # 派生類中訪問 obj = C() obj.foo # 通過對象訪問 obj.func() # 類內部訪問 obj_son = D(); obj_son.show() # 派生類中訪問 公有普通字段

class C: def __init__(self): self.__foo = "私有字段" def func(self): print self.foo # 類內部訪問 class D(C): def show(self): print self.foo # 派生類中訪問 obj = C() obj.__foo # 通過對象訪問 ==> 錯誤 obj.func() # 類內部訪問 ==> 正確 obj_son = D(); obj_son.show() # 派生類中訪問 ==> 錯誤 私有普通字段
方法:
- 公有方法:對象可以訪問;類內部可以訪問;派生類中可以訪問
- 私有方法:僅類內部可以訪問;

class C: def __init__(self): pass def add(self): print('in C') class D(C): def show(self): print('in D') def func(self): self.show() obj = D() obj.show() # 通過對象訪問 obj.func() # 類內部訪問 obj.add() # 派生類中訪問 公有方法

class C: def __init__(self): pass def __add(self): print('in C') class D(C): def __show(self): print('in D') def func(self): self.__show() obj = D() obj.__show() # 通過不能對象訪問 obj.func() # 類內部可以訪問 obj.__add() # 派生類中不能訪問
總結:
對於這些私有成員來說,他們只能在類的內部使用,不能再類的外部以及派生類中使用.
ps:非要訪問私有成員的話,可以通過 對象._類__屬性名,但是絕對不允許!!!
為什么可以通過._類__私有成員名訪問呢?因為類在創建時,如果遇到了私有成員(包括私有靜態字段,私有普通字段,私有方法)它會將其保存在內存時自動在前面加上_類名.
三. 類的其他成員
這里的其他成員主要就是類方法:
方法包括:普通方法、靜態方法和類方法,三種方法在內存中都歸屬於類,區別在於調用方式不同。
實例方法
定義:第一個參數必須是實例對象,該參數名一般約定為“self”,通過它來傳遞實例的屬性和方法(也可以傳類的屬性和方法);
調用:只能由實例對象調用。
類方法
定義:使用裝飾器@classmethod。第一個參數必須是當前類對象,該參數名一般約定為“cls”,通過它來傳遞類的屬性和方法(不能傳實例的屬性和方法);
調用:實例對象和類對象都可以調用。
靜態方法
定義:使用裝飾器@staticmethod。參數隨意,沒有“self”和“cls”參數,但是方法體中不能使用類或實例的任何屬性和方法;
調用:實例對象和類對象都可以調用。
雙下方法(后面會講到)
定義:雙下方法是特殊方法,他是解釋器提供的 由爽下划線加方法名加爽下划線 __方法名__的具有特殊意義的方法,雙下方法主要是python源碼程序員使用的,
我們在開發中盡量不要使用雙下方法,但是深入研究雙下方法,更有益於我們閱讀源碼。
調用:不同的雙下方法有不同的觸發方式,就好比盜墓時觸發的機關一樣,不知不覺就觸發了雙下方法,例如:__init__
實例方法
簡而言之,實例方法就是類的實例能夠使用的方法。這里不做過多解釋。
3.1 類方法
使用裝飾器@classmethod。
原則上,類方法是將類本身作為對象進行操作的方法。假設有個方法,且這個方法在邏輯上采用類本身作為對象來調用更合理,那么這個方法就可以定義為類方法。另外,如果需要繼承,也可以定義為類方法。
如下場景:
假設我有一個學生類和一個班級類,想要實現的功能為:
執行班級人數增加的操作、獲得班級的總人數;
學生類繼承自班級類,每實例化一個學生,班級人數都能增加;
最后,我想定義一些學生,獲得班級中的總人數。
思考:這個問題用類方法做比較合適,為什么?因為我實例化的是學生,但是如果我從學生這一個實例中獲得班級總人數,在邏輯上顯然是不合理的。同時,如果想要獲得班級總人數,如果生成一個班級的實例也是沒有必要的。
class Student:
__num = 0
def __init__(self,name,age):
self.name = name
self.age= age
Student.addNum() # 寫在__new__方法中比較合適,但是現在還沒有學,暫且放到這里
@classmethod
def addNum(cls):
cls.__num += 1
@classmethod
def getNum(cls):
return cls.__num
a = Student('太白金星', 18)
b = Student('武sir', 36)
c = Student('alex', 73)
print(Student.getNum())
3.2 靜態方法
使用裝飾器@staticmethod。
靜態方法是類中的函數,不需要實例。靜態方法主要是用來存放邏輯性的代碼,邏輯上屬於類,但是和類本身沒有關系,也就是說在靜態方法中,不會涉及到類中的屬性和方法的操作。可以理解為,靜態方法是個獨立的、單純的函數,它僅僅托管於某個類的名稱空間中,便於使用和維護。
譬如,我想定義一個關於時間操作的類,其中有一個獲取當前時間的函數。
import time class TimeTest(object): def __init__(self, hour, minute, second): self.hour = hour self.minute = minute self.second = second @staticmethod def showTime(): return time.strftime("%H:%M:%S", time.localtime()) print(TimeTest.showTime()) t = TimeTest(2, 10, 10) nowTime = t.showTime() print(nowTime)
如上,使用了靜態方法(函數),然而方法體中並沒使用(也不能使用)類或實例的屬性(或方法)。若要獲得當前時間的字符串時,並不一定需要實例化對象,此時對於靜態方法而言,所在類更像是一種名稱空間。
其實,我們也可以在類外面寫一個同樣的函數來做這些事,但是這樣做就打亂了邏輯關系,也會導致以后代碼維護困難。
3.3 屬性
什么是特性property
property是一種特殊的屬性,訪問它時會執行一段功能(函數)然后返回值
例一:BMI指數(bmi是計算而來的,但很明顯它聽起來像是一個屬性而非方法,如果我們將其做成一個屬性,更便於理解) 成人的BMI數值: 過輕:低於18.5 正常:18.5-23.9 過重:24-27 肥胖:28-32 非常肥胖, 高於32 體質指數(BMI)=體重(kg)÷身高^2(m) EX:70kg÷(1.75×1.75)=22.86

class People: def __init__(self,name,weight,height): self.name=name self.weight=weight self.height=height @property def bmi(self): return self.weight / (self.height**2) p1=People('egon',75,1.85) print(p1.bmi) 例一代碼
為什么要用property
將一個類的函數定義成特性以后,對象再去使用的時候obj.name,根本無法察覺自己的name是執行了一個函數然后計算出來的,這種特性的使用方式遵循了統一訪問的原則
由於新式類中具有三種訪問方式,我們可以根據他們幾個屬性的訪問特點,分別將三個方法定義為對同一個屬性:獲取、修改、刪除

class Foo: @property def AAA(self): print('get的時候運行我啊') @AAA.setter def AAA(self,value): print('set的時候運行我啊') @AAA.deleter def AAA(self): print('delete的時候運行我啊') #只有在屬性AAA定義property后才能定義AAA.setter,AAA.deleter f1=Foo() f1.AAA f1.AAA='aaa' del f1.AAA 或者: class Foo: def get_AAA(self): print('get的時候運行我啊') def set_AAA(self,value): print('set的時候運行我啊') def delete_AAA(self): print('delete的時候運行我啊') AAA=property(get_AAA,set_AAA,delete_AAA) #內置property三個參數與get,set,delete一一對應 f1=Foo() f1.AAA f1.AAA='aaa' del f1.AAA

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 # 刪除商品原價 商品實例
四. isinstace 與 issubclass

class A: pass class B(A): pass obj = B() print(isinstance(obj,B)) print(isinstance(obj,A))
isinstance(a,b):判斷a是否是b類(或者b類的派生類)實例化的對象

class A: pass class B(A): pass class C(B): pass print(issubclass(B,A)) print(issubclass(C,A))
issubclass(a,b): 判斷a類是否是b類(或者b的派生類)的派生類
思考:那么 list str tuple dict等這些類與 Iterble類 的關系是什么?

from collections import Iterable print(isinstance([1,2,3], list)) # True print(isinstance([1,2,3], Iterable)) # True print(issubclass(list,Iterable)) # True # 由上面的例子可得,這些可迭代的數據類型,list str tuple dict等 都是 Iterable的子類。
課外了解:元類type。
按照Python的一切皆對象理論,類其實也是一個對象,那么類這個對象是從哪里實例化出來的呢?

print(type('abc')) print(type(True)) print(type(100)) print(type([1, 2, 3])) print(type({'name': '太白金星'})) print(type((1,2,3))) print(type(object)) class A: pass print(isinstance(object,type)) print(isinstance(A, type))
type元類是獲取該對象從屬於的類,而type類比較特殊,Python原則是:一切皆對象,其實類也可以理解為'對象',而type元類又稱作構建類,python中大多數內置的類(包括object)以及自己定義的類,都是由type元類創造的。
* 而type類與object類之間的關系比較獨特:object是type類的實例,而type類是object類的子類,這種關系比較神奇無法使用python的代碼表述,因為定義其中一個之前另一個必須存在。所以這個只作為了解。