1、類與對象的概念
類即類別、種類,是面向對象設計最重要的概念,從一小節我們得知對象是特征與技能的結合體,而類則是一系列對象相似的特征與技能的結合體。
那么問題來了,先有的一個個具體存在的對象(比如一個具體存在的人),還是先有的人類這個概念,這個問題需要分兩種情況去看
(1)在現實世界中:肯定是先有對象,再有類世界上肯定是先出現各種各樣的實際存在的物體,然后隨着人類文明的發展,人類站在不同的角度總結出了不同的種類,比如
人類、動物類、植物類等概念。也就說,對象是具體的存在,而類僅僅只是一個概念,並不真實存在,比如你無法告訴我人類
具體指的是哪一個人。
(2)在程序中:務必保證先定義類,后產生對象
這與函數的使用是類似的:先定義函數,后調用函數,類也是一樣的:在程序中需要先定義類,后調用類。不一樣的是:調用
函數會執行函數體代碼返回的是函數體執行的結果,而調用類會產生對象,返回的是對象
1>把一類事物的靜態屬性和動態可以執行的操作組合在一起所得到的這個概念就是類 2>類的一個個體就是對象,對象是具體的,實實在在的事物 3>對象是特征與技能的結合體,其中特征和技能分別對應對象的數據屬性和方法屬性 4>對象(實例)本身只有數據屬性,但是python的class機制會將類的函數綁定到對象上,稱為對象的方法,或者叫綁定方法,綁定方法唯一綁定一個對象,同一個類的方法綁定到不同的對象上,屬於不同的方法,內存地址都不會一樣 在類內部定義的屬性屬於類本身的,由操作系統只分配一塊內存空間,大家公用這一塊內存空間 5>創建一個類就會創建一個類的名稱空間,用來存儲類中定義的所有名字,這些名字稱為類的屬性:而類中有兩種屬性:數據屬性和函數屬性,其中類的數據屬性是共享給所有對象的,而類的函數屬性是綁定到所有對象的。 6>創建一個對象(實例)就會創建一個對象(實例)的名稱空間,存放對象(實例)的名字,稱為對象(實例)的屬性 7>在obj.name會先從obj自己的名稱空間里找name,找不到則去類中找,類也找不到就找父類…最后都找不到就拋出異常。 8>類的相關方法: 類的相關方法(定義一個類,也會產生自己的名稱空間) 類名.__name__ # 類的名字(字符串)
類名.__doc__ # 類的文檔字符串
類名.__base__ # 類的第一個父類(在講繼承時會講)
類名.__bases__ # 類所有父類構成的元組(在講繼承時會講)
類名.__dict__ # 類的字典屬性、名稱空間
類名.__module__ # 類定義所在的模塊
類名.__class__ # 實例對應的類(僅新式類中)
1.創建出類會產生名稱空間,實例化對象也會產生名稱空間。 2.用戶自己定義的一個類,實際上就是定義了一個類型,類型與類是統一的。 3.用戶先是從自己的命名空間找,如果找不大,在從類的命名空間找。 student1.langage = "1111"
print(student1.__dict__) ===>先是從自己的命名空間找 print(Student.__dict__) ===>然后在從類的命名空間找 4.通過類來訪問,訪問的是函數,通過對象來訪問,訪問的是方法,在類內部定義的方式實際上是綁定到對象的身上來用的。 <function Student.fun at 0x000000000267DAE8>
<bound method Student.fun of <__main__.Student object at 0x0000000002684128>>
<function Student.fun at 0x00000000025CDAE8>
<bound method Student.fun of <__main__.Student object at 0x00000000025D4160>>
<bound method Student.fun of <__main__.Student object at 0x00000000025D4198>>
5.總結:類的數據屬性是大家共有的,而且大家的內部地址是一樣的,用的就是一個 類的函數屬性是綁定到大家身上的,內部地址不一樣,綁定方法指的是綁定到對象身上。 綁定方法:綁定到誰的身上,就是給誰用的,誰來調用就會自動把自己當做第一個參數傳入。 **定義在類內部的變量,是所有對象共有的,id全一樣, **定義在類內部的函數,是綁定到所有對象的,是給對象來用的,obj.fun()會把obj本身當做 一個參數來傳遞。 6.在類內部定義的函數雖然可以由類來調用,但是並不是為了給類用的,在類內部定義的函數的目的就是為了綁定到對象身上的。 7.在類的內部來說,__init__是類的函數屬性,但是對於對象來說,就是綁定方法。 8.命名空間的問題:先從對象的命名空間找,隨后在從類的命名空間找,隨后在從父類的命名 空間找。 print(student1.x) 9.在定義類的時候,可以想什么先寫什么。
2、定義類
按照上述步驟,我們來定義一個類
(1)在現實世界中,先有對象,再有類
對象1:李坦克 特征: 學校=oldboy 姓名=李坦克 性別=男 年齡=18 技能: 學習 吃飯 睡覺 對象2:王大炮 特征: 學校=oldboy 姓名=王大炮 性別=女 年齡=38 技能: 學習 吃飯 睡覺 對象3:牛榴彈 特征: 學校=oldboy 姓名=牛榴彈 性別=男 年齡=78 技能: 學習 吃飯 睡覺
(2)在程序中,必須先定義類,后使用類(用來產生對象)
#在Python中程序中的類用class關鍵字定義,而在程序中特征用變量標識,技能用函數標識,因而類中最常見的無非是:變量和函數的定義
# 先定義類
class OldboyStudent: school='oldboy' def learn(self): print('is learning') def eat(self): print('is eating') def sleep(self): print('is sleeping')
# 后產生對象
stu1 = OldboyStudent()
stu2 = OldboyStudent()
stu3 = OldboyStudent()
print(stu1)
print(stu2)
print(stu3)
- 類中可以有任意python代碼,這些代碼在類定義階段便會執行,因而會產生新的名稱空間,用來存放類的變量名與函數名,可以通過OldboyStudent.__dict__查看
- 類中定義的名字,都是類的屬性,點是訪問屬性的語法。
- 對於經典類來說我們可以通過該字典操作類名稱空間的名字,但新式類有限制(新式類與經典類的區別我們將在后續章節介紹
3、類的使用
3.1、引用類的屬性
class OldboyStudent:
school='oldboy'
def learn(self):
print('is learning')
def eat(self):
print('is eating')
def sleep(self):
print('is sleeping')
# 后產生對象
stu1 = OldboyStudent()
stu2 = OldboyStudent()
stu3 = OldboyStudent()
print(stu1)
print(stu2)
print(stu3)
print(OldboyStudent.school) #查 輸出結果:oldboy
OldboyStudent.school='Oldboy2' #改
print(OldboyStudent.school)# 輸出結果:Oldboy2
OldboyStudent.x=1 #增
print(OldboyStudent.x) #輸出結果 1
del OldboyStudent.x #刪
print(OldboyStudent.x)
輸出結果:
AttributeError: type object 'OldboyStudent' has no attribute 'x'
3.2、調用類,或稱為實例化,得到程序中的對象
stu1 = OldboyStudent()
stu2 = OldboyStudent()
stu3 = OldboyStudent()
#如此,s1、s2、s3都一樣了,而這三者除了相似的屬性之外還各種不同的屬性,這就用到了__init__
__init__方法 # 用來為對象定制自己獨特的屬性 #注意:該方法是在對象產生之后才會執行,只用來為對象進行初始化操作,可以有任意代碼,但一定不能有返回值
class OldboyStudent: ...... def __init__(self,name,age,sex): self.name=name self.sex=sex self.age=age ...... s1=OldboyStudent('李坦克','男',18) #先調用類產生空對象s1,然后調用OldboyStudent.__init__(s1,'李坦克','男',18) s2=OldboyStudent('王大炮','女',38) s3=OldboyStudent('牛榴彈','男',78)
4、對象的使用
class OldboyStudent: school = 'oldboy' def __init__(self,name,sex,age): self.name=name self.sex=sex self.age = age def learn(self): print('is learning') def eat(self): print('is eating') def sleep(self): print('is sleeping') s1=OldboyStudent('李坦克','男',18) #先調用類產生空對象s1,然后調用OldboyStudent.__init__(s1,'李坦克','男',18) s2=OldboyStudent('王大炮','女',38) s3=OldboyStudent('牛榴彈','男',78) print(s1.__dict__) print(s2.__dict__) print(s3.__dict__) 結果: {'name': '李坦克', 'sex': '男', 'age': 18} {'name': '王大炮', 'sex': '女', 'age': 38} {'name': '牛榴彈', 'sex': '男', 'age': 78}
#執行__init__,s1.name='牛榴彈',很明顯也會產生對象的名稱空間可以用s2.__dict__查看,查看結果為 {'name': '王大炮', 'age': '女', 'sex': 38} s2.name #查,等同於s2.__dict__['name'] s2.name='王三炮' #改,等同於s2.__dict__['name']='王三炮' s2.course='python' #增,等同於s2.__dict__['course']='python' del s2.course #刪,等同於s2.__dict__.pop('course')
5、補充說明
- 站的角度不同,定義出的類是截然不同的;
- 現實中的類並不完全等於程序中的類,比如現實中的公司類,在程序中有時需要拆分成部門類,業務類等;
- 有時為了編程需求,程序中也可能會定義現實中不存在的類,比如策略類,現實中並不存在,但是在程序中卻是一個很常見的類。