1)類是一類抽象的事物,物件是一個具體的事物;用類建立物件的過程,稱為範例化。
2)類就是一個模子,只知道在這個模子裡有什麼屬性、什麼方法,但是不知道這些屬性、方法具體是什麼;
所以,我們要在這個模子的基礎上 造出一個具體的範例(物件),這個範例就會具體化屬性、方法
3)所有的資料型別都是類,都是抽象的;根據資料型別定義變數,該變數就是一個具體的值(物件)。
程式導向 --> 物件導向的轉變
定義一個函數 《==》 定義一個類
函數的返回值(字典) 《==》類的物件(類似字典,只不過呼叫方式發生了改變)
函數的執行過程 《==》類的範例化
請看 程式碼展示1 和 程式碼展示2
1 # 用物件導向的思想、程式導向的語法 去實現 Rectangle的計算 2 def Rectangle(length=0, width=0): 3 self = {} # 儲存屬性值 4 def __init__(*args): # 初始化函數 -- 完成對矩陣rectangle的長、寬初始化,以及面積、周長的呼叫方式 5 self['length'] = args[0] 6 self['width'] = args[1] 7 self['area'] = area 8 self['perimeter'] = perimeter 9 def area(): 10 return self['length'] * self['width'] 11 def perimeter(): 12 return 2 * (self['length'] + self['width']) 13 __init__(length, width) # 呼叫初始化函數 14 return self 15 16 rec_obj = Rectangle(10,5) # rec_obj 相當於類的一個範例 17 print(rec_obj) # rec_obj中存放了範例的屬性、方法,通過範例可以檢視屬性 與 呼叫方法 18 print('length:%s, width:%s, area:%s, perimeter:%s'\ 19 %(rec_obj['length'], rec_obj['width'], rec_obj['area'](), rec_obj['perimeter']()))
1 class Rectangle: 2 temVar = 'over' #定義靜態屬性,共用於類中的每個物件 3 def __init__(self, *args): # 建立物件後執行的第一個函數,self就是類建立的物件,該函數返回類的物件self 4 self.length = args[0] 5 self.width = args[1] 6 def area(self): 7 return self.length * self.width 8 def perimeter(self): 9 return 2 * (self.length + self.width) 10 11 rec_obj1 = Rectangle(10, 5) # 範例化一個具體物件 12 13 # 通過 物件 檢視屬性(包括靜態屬性)與呼叫方法 14 print('length:%s, width:%s, area:%s, perimeter:%s'\ 15 %(rec_obj1.length, rec_obj1.width, rec_obj1.area(), rec_obj1.perimeter())) 16 print(rec_obj1.temVar) # 靜態屬性 17 18 # 通過 類名 呼叫方法 、類中的靜態屬性 19 print('area:%s, perimeter:%s'%( Rectangle.area(rec_obj1), Rectangle.perimeter(rec_obj1))) 20 print(Rectangle.temVar) # 靜態屬性 21 22 # 通過物件名修改屬性(若self裡 存在該屬性,是修改;若self裡 不存在該屬性,是新增新屬性) 23 # rec_obj1.length = 20 24 # rec_obj1.temVar = 'object_over' # 給物件中新增一個新屬性 'temVar': 'object_over' 25 # 通過類名修改屬性(若類裡 存在該屬性<靜態屬性>,是修改;若類裡 不存在該屬性,是新增新屬性,<靜態屬性>) 26 # Rectangle.length = 50 # 在類中新增一個新屬性 'length': 50 27 # Rectangle.temVar = 'class_over' 28 29 # __dict__的使用 30 print(rec_obj1.__dict__) # 檢視物件的所有屬性,即self屬性 31 print(Rectangle.__dict__) # 檢視類的所有靜態屬性、方法 32 # __dict__ 對於 物件的 增刪改查操作都可以通過字典的語法進行 33 # __dict__ 對於 類中的名字只能看 不能操作
22 # 通過物件名修改屬性(若self裡 存在該屬性,是修改;若self裡 不存在該屬性,是新增新屬性)
23 # rec_obj1.length = 20
24 # rec_obj1.temVar = 'object_over' # 給物件中新增一個新屬性 'temVar': 'object_over'
25 # 通過類名修改屬性(若類裡 存在該屬性<靜態屬性>,是修改;若類裡 不存在該屬性,是新增新屬性,<靜態屬性>)
26 # Rectangle.length = 50 # 在類中新增一個新屬性 'length': 50
27 # Rectangle.temVar = 'class_over'
總結:
# 物件 = 類名()
# 範例化的過程:
# 類名() -> 會創造出一個物件,即建立了一個self變數
# 呼叫__init__(self)方法,類名括號裡的引數會被這裡接收
# 執行__init__(self)方法
# 返回self
# 物件能做的事:
# 檢視屬性(自己的屬性 和 類中靜態屬性)
# 呼叫方法
# __dict__ 對於物件的增刪改查操作都可以通過字典的語法進行
# 類名能做的事:
# 範例化
# 呼叫類中的屬性,也就是呼叫靜態屬性
# 呼叫方法 : 只不過要自己傳遞self引數
# __dict__ 對於類中的名字只能看 不能操作
建立一個類,就會自動建立一個該類的名稱空間,在該名稱空間中儲存類的屬性(靜態屬性、動態屬性(方法));
靜態屬性:直接在類中定義的變數;(靜態屬性屬於類,即屬於所有物件)
動態屬性:在類中定義的函數;(動態屬性繫結到所有物件)
範例化一個物件,就會自動建立一個該物件的名稱空間,在該名稱空間中存放物件的屬性;同時,在範例化之後,就後產生一個指向類物件指標,用來指向當前物件所屬類的名稱空間,這樣就可以存取類的靜態屬性與動態屬性。
在物件尋找屬性的過程中,優先從物件的名稱空間中搜尋,然後去類的名稱空間中查詢,最後在父類別的名稱空間中查詢...,若沒有找到該屬性,程式就會丟擲異常。
注:類與物件的名稱空間是獨立儲存的
完整程式碼展示:
class Family: ''' 定義一個公共賬號 ,只要有人上班,就將錢存到這個賬號上 ''' share_money = 0 # 不可變資料型別做靜態屬性 native_place = ['china'] # 可變資料型別做靜態屬性 def __init__(self, role, name, salary): self.role = role self.name = name self.salary = salary def work(self): Family.share_money += self.salary # 將每個的錢都存放到這個公共賬號上 print('the account remains ¥%s '%Family.share_money) member1 = Family('father', 'lilei', 1000) member2 = Family('mother', 'zhanghua', 500) member1.work() # the account remains ¥1000 member2.work() # the account remains ¥1500 member1.share_money = 200 # 為自己獨立開了個小金庫,並存入200元 -- 在物件member1中新增這一屬性 member1.share_money += 100 # 以後就可以在自己的小金庫中存放私房錢,即總金額=200+100=300 member2.share_money += 400 # 將公有賬號作為自己的私有賬號,並存入400元,即總金額=1000+500+400=1900 print(Family.share_money) # 1000+500=1500 print(member1.share_money) # 200+100=300 print(member2.share_money) # 1000+500+400=1900 """ 可變資料型別做靜態屬性的影響: Family.native_place = 'america' # member1.native_place[0] = 'america' # 修改的是類中的native_place,會影響所有物件(同上) # member2.native_place[0] = 'america' # 修改的是類中的native_place,會影響所有物件(同上) print(member1.__dict__) print(member2.__dict__) print(Family.__dict__) {'role': 'father', 'name': 'lilei', 'salary': 1000, 'share_money': 300} {'role': 'mother', 'name': 'zhanghua', 'salary': 500, 'share_money': 1900} {'__module__': '__main__', '__doc__': '\n 定義一個公共賬號 ,只要有人上班,就將錢存到這個賬號上\n ', 'share_money': 1500, 'native_place': ['america'], '__init__': <function Family.__init__ at 0x0000021C360084C8>, 'work': <function Family.work at 0x0000021C3629C048>, '__dict__': <attribute '__dict__' of 'Family' objects>, '__weakref__': <attribute '__weakref__' of 'Family' objects>} """ """ 可變資料型別做靜態屬性的影響: member1.native_place = 'america' # 重新賦值,在當前物件的名稱空間中新增這個屬性,不會影響其它物件 print(member1.__dict__) print(member2.__dict__) print(Family.__dict__) {'role': 'father', 'name': 'lilei', 'salary': 1000, 'share_money': 300, 'native_place': 'america'} {'role': 'mother', 'name': 'zhanghua', 'salary': 500, 'share_money': 1900} {'__module__': '__main__', '__doc__': '\n 定義一個公共賬號 ,只要有人上班,就將錢存到這個賬號上\n ', 'share_money': 1500, 'native_place': ['china'], '__init__': <function Family.__init__ at 0x000002E4747684C8>, 'work': <function Family.work at 0x000002E4749FC048>, '__dict__': <attribute '__dict__' of 'Family' objects>, '__weakref__': <attribute '__weakref__' of 'Family' objects>} """
(1)對於不可變資料型別來說,最好用類名操作靜態屬性;
若用物件名操作靜態屬性,其修改 和 重新賦值 都是獨立的(獨立的:物件與類的名稱空間分開存放)
1)若用物件名第一次修改靜態屬性,首先會到類的名稱空間中找到該靜態屬性的屬性值,然後在當前物件的名稱空間中再做修改
2)若用物件名直接給靜態屬性重新賦值,那麼直接會在當前物件的名稱空間中新增這一屬性
(2)對於可變資料型別來說,用物件名修改是 共用的, 用物件名重新賦值是 獨立的
因為修改的是指標變數所指向記憶體中的值,故是 共用的
!!!總結,操作靜態屬性,最好用類名操作靜態屬性;
不可變資料型別:對於相同的值對應的記憶體地址是不變的;
1 a = 1 2 b = 1 3 c = 2 4 d = a + b 5 print(" id(a) = %d\n id(b) = %d\n id(c) = %d\n id(d) = %d\n" 6 % (id(a), id(b), id(c), id(d))) 7 8 """ 9 id(a) = 1461563616 10 id(b) = 1461563616 11 id(c) = 1461563648 12 id(d) = 1461563648 13 """
可變的資料型別:對於相同值的記憶體地址是可變的;
1 al = [1, 2, 3] 2 bl = [1, 2, 3] 3 print(" id(al) = %d\n id(bl) = %d\n" % (id(al), id(bl))) 4 al.append(4) 5 bl += [4] 6 print(" id(al) = %d\n id(bl) = %d\n" % (id(al), id(bl))) 7 print(" al:%s\n bl:%s\n" % (al, bl)) 8 9 """ 10 id(al) = 2353965003720 11 id(bl) = 2353964735816 12 13 id(al) = 2353965003720 14 id(bl) = 2353964735816 15 16 al:[1, 2, 3, 4] 17 bl:[1, 2, 3, 4] 18 """
一:我們定義的類的屬性到底存到哪裡了?有兩種方式檢視 dir(類名):查出的是一個名字列表 類名.__dict__:查出的是一個字典,key為屬性名,value為屬性值 二:特殊的類屬性 類名.__name__ # 類的名字(字串) 類名.__doc__ # 類的檔案字串 類名.__base__ # 類的第一個父類別 類名.__bases__ # 類所有父類別構成的元組 類名.__dict__ # 類的字典屬性 類名.__module__ # 類定義所在的模組 類名.__class__ # 範例對應的類(僅新式類中)
""" 物件名.__dict__:檢視物件的屬性(self物件中儲存的變數) 類名.__dict__:檢視類的屬性(在類中能看到的靜態屬性與動態屬性) dir(物件名):檢視物件的所有屬性(此時包括self物件、類屬性、內建方法) dir(類名):檢視類的所有屬性(不包括self物件) 注:在繼承中,子類名.__dict__中看不到父類別中的類屬性,但實際上包括父類別的類屬性 """
案例分析
class Family: ''' 定義一個公共賬號 ,只要有人上班,就將錢存到這個賬號上 ''' share_money = 0 # 不可變資料型別做靜態屬性 native_place = ['china'] # 可變資料型別做靜態屬性 def __init__(self, role, name, salary): self.role = role self.name = name self.salary = salary def work(self): Family.share_money += self.salary # 將每個人的錢都存放到這個公共賬號上 print('the account remains ¥%s '%Family.share_money) def fun(self): pass class NewFamily(Family): new_account = 0 def __init__(self, role, name, salary, kind): super(NewFamily, self).__init__(role, name, salary) self.kind = kind def work(self): pass # 使用__定義私有屬性 # python中不存在嚴格的私有屬性,在類的外部可通過正真的函數名【_類名__函數名,即 _NewFamily__expenditure】間接呼叫 def __expenditure(self): pass f = Family('father', 'lilei', 1000) nf = NewFamily("son", "liwei", 2000, "salesman") print("-"*20, "nf.__dict__ 與 f.__dict__ 對比", "-"*20) print(f.__dict__) print(nf.__dict__) print(set(nf.__dict__) - set(f.__dict__)) print("-"*20, "NewFamily.__dict__ 與 Family.__dict__ 對比", "-"*20) print(Family.__dict__) print(NewFamily.__dict__) print(set(NewFamily.__dict__) - set(Family.__dict__)) print("-"*20, "dir(nf) 與 dir(f) 對比", "-"*20) print(dir(f)) print(dir(nf)) print(set(dir(nf)) - set(dir(f))) print("-"*20, "dir(NewFamily) 與 dir(Family) 對比", "-"*20) print(dir(Family)) print(dir(NewFamily)) print(set(dir(NewFamily)) - set(dir(Family)))
輸出結果:
""" -------------------- nf.__dict__ 與 f.__dict__ 對比 -------------------- {'role': 'father', 'name': 'lilei', 'salary': 1000} {'role': 'son', 'name': 'liwei', 'salary': 2000, 'kind': 'salesman'} {'kind'} -------------------- NewFamily.__dict__ 與 Family.__dict__ 對比 -------------------- {'__module__': '__main__', '__doc__': '\n 定義一個公共賬號 ,只要有人上班,就將錢存到這個賬號上\n ', 'share_money': 0, 'native_place': ['china'], '__init__': <function Family.__init__ at 0x000001EC8159D288>, 'work': <function Family.work at 0x000001EC8159D318>, 'fun': <function Family.fun at 0x000001EC8159D3A8>, '__dict__': <attribute '__dict__' of 'Family' objects>, '__weakref__': <attribute '__weakref__' of 'Family' objects>} {'__module__': '__main__', 'new_account': 0, '__init__': <function NewFamily.__init__ at 0x000001EC8159D438>, 'work': <function NewFamily.work at 0x000001EC8159D4C8>, '_NewFamily__expenditure': <function NewFamily.__expenditure at 0x000001EC8159D558>, '__doc__': None} {'_NewFamily__expenditure', 'new_account'} -------------------- dir(nf) 與 dir(f) 對比 -------------------- ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'fun', 'name', 'native_place', 'role', 'salary', 'share_money', 'work'] ['_NewFamily__expenditure', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'fun', 'kind', 'name', 'native_place', 'new_account', 'role', 'salary', 'share_money', 'work'] {'_NewFamily__expenditure', 'new_account', 'kind'} -------------------- dir(NewFamily) 與 dir(Family) 對比 -------------------- ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'fun', 'native_place', 'share_money', 'work'] ['_NewFamily__expenditure', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'fun', 'native_place', 'new_account', 'share_money', 'work'] {'_NewFamily__expenditure', 'new_account'} """