一:三大編程范式
1.面向過程編程 2.函數式編程 3.面向對象編程
(類:把一類事物的相同的特征和動作整合到一起就是類,類是一個抽象的概念)
(對象:就是基於類而創建的一個具體的事物 [具體存在的] 也是特征和動作整合到一起)
二:類與對象
(在python2中,分新式類與經典類,python3統一都是新式類【新式類,class 類名:】【經典類,class 類名(object)】)

class Chinese: #class是關鍵字,表示類名 pass print(Chinese) p1=Chinese() #實例化過程,創建對象,類名后面加括號 print(p1)
實例化,由類產生對象的過程叫做實例化,類實例化的結果就是一個對象,或者叫做一個實例
ps:類中的函數第一個參數必須是self 類中定義的函數叫做 “方法”

類是用來描述一類事物,類的對象指的是這一類事物中的一個個體 是事物就要有屬性,屬性分為: 1.數據屬性:就是變量 2.函數屬性:就是函數,在面向對象里通常稱為方法 注:類和對象均是用點來訪問自己的屬性

類是用來描述一類事物,類的對象指的是這一類事物中的一個個體 是事物就要有屬性,屬性分為: 1.數據屬性:就是變量 2.函數屬性:就是函數,在面向對象里通常稱為方法 注:類和對象均是用點來訪問自己的屬性
1 class Chinese: 2 dang='我愛中國' 3 def tu_tan(): 4 print('張口就是一痰') 5 def queue(self): 6 print('隨意就是一插') 7 print(Chinese.dang) #調用類Chinese的數據屬性 8 Chinese.tu_tan() #調用方法 9 Chinese.queue('zy') #queue方法必須傳一個參數 10 print(Chinese.__dict__) #Chinese所有的方法 11 print(Chinese.__dict__['dang']) #在字典中找出了dang這個數據屬性 12 print(Chinese.__dict__['tu_tan']) #內存地址,加()就是地址的內容 13 Chinese.__dict__['tu_tan']() 14 Chinese.__dict__['queue'](666) #必須給queue傳一個參數 15 16 # 我愛中國 17 # 張口就是一痰 18 # 隨意就是一插 19 # {'__dict__': <attribute '__dict__' of 'Chinese' objects>, '__module__': '__main__', 'queue': <function Chinese.queue at 0x0000029230A14C80>, 'tu_tan': <function Chinese.tu_tan at 0x0000029230A148C8>, 'dang': '我愛中國', '__doc__': None, '__weakref__': <attribute '__weakref__' of 'Chinese' objects>} 20 # 我愛中國 21 # <function Chinese.tu_tan at 0x0000029230A148C8> 22 # 張口就是一痰 23 # 隨意就是一插
對象:
1 class Chinese: 2 dang='我愛中國' 3 # def __init__(name,age,gender): #開頭結尾都有兩個_ _表示是系統內置的方法 4 # dic={ 5 # 'name':name, 6 # 'age':age, 7 # 'gender':gender 8 # } 9 # return dic 10 def __init__(self,name,age,gender): 11 print('開始') 12 self.mingzi=name # 其實就是字典中封裝了名字,年級,性別 13 self.nianji=age 14 self.xingbie=gender 15 print('結束') 16 #class的__init__就是不需要返回任何值,它會自動返回 17 def tu_tan(): 18 print('張口就是一痰') 19 def queue(self): 20 print('隨意就是一插') 21 22 person1=Chinese('zy',18,'female') #實例化就是在觸發系統內置的__init__ 23 print(person1.__dict__) #實例化后的字典形式 __dict__ 24 print(person1.mingzi) #調用person1字典的mingzi 25 print(person1.dang) #person1調用類class的屬性 26 27 Chinese.tu_tan() 28 Chinese.queue(person1) #必須傳參數 29 30 結果: 31 # 開始 32 # 結束 33 # {'xingbie': 'female', 'nianji': 18, 'mingzi': 'zy'} 34 # zy 35 # 我愛中國 36 # 張口就是一痰 37 # 隨意就是一插
類屬性的增刪改查:
1 class Chinese: 2 country='China' 3 def __init__(self,name): 4 self.name=name 5 def play_ball(self,ball): 6 print("%s 正在打%s" %(self.name,ball)) 7 8 print(Chinese.country) #查看 9 10 Chinese.country='Japan' 11 print(Chinese.country) #修改 12 13 p1=Chinese('alex') 14 print(p1.__dict__) 15 print(p1.country) 16 17 Chinese.dang='dang' #增加 18 print(Chinese.dang) 19 print(p1.dang) 20 21 del Chinese.dang #刪除 22 del Chinese.country 23 print(Chinese.__dict__) 24 25 結果: 26 # China 27 # Japan 28 # {'name': 'alex'} 29 # Japan 30 # dang 31 # dang 32 # {'__module__': '__main__', '__init__': <function Chinese.__init__ at 0x000001FE771948C8>, '__weakref__': <attribute '__weakref__' of 'Chinese' objects>, '__dict__': <attribute '__dict__' of 'Chinese' objects>, 'play_ball': <function Chinese.play_ball at 0x000001FE77194C80>, '__doc__': None}
實例屬性的增刪改查: (實例只有數據屬性)
1 class Chinese: 2 country='China' 3 def __init__(self,name): 4 self.name=name 5 def play_ball(self,ball): 6 print("%s 正在打%s" %(self.name,ball)) 7 p1=Chinese('alex') 8 print(p1.__dict__) #實例屬性只有{'name': 'alex'} 9 10 #查看 11 print(p1.name) 12 print(p1.play_ball) #這一步實際上是訪問類 13 14 #增加 15 p1.age=18 16 print(p1.__dict__) 17 print(p1.age) 18 19 #修改 20 p1.age=19 21 print(p1.__dict__) 22 print(p1.age) 23 24 #刪除 25 del p1.age 26 print(p1.__dict__) 27 28 結果: 29 #{'name': 'alex'} 30 # alex 31 # <bound method Chinese.play_ball of <__main__.Chinese object at 0x000002042B47A400>> 32 # {'age': 18, 'name': 'alex'} 33 # 18 34 # {'age': 19, 'name': 'alex'} 35 # 19 36 # {'name': 'alex'}
對象與實例屬性:
1 class Chinese: 2 country='China' 3 def __init__(self,name): 4 self.name=name 5 def play_ball(self,ball): 6 print("%s 正在打%s" %(self.name,ball)) 7 p1=Chinese('alex') 8 print(p1.country) 9 p1.country='Japan' 10 print(Chinese.country) #類的 11 print(p1.country) #實例的 12 結果: 13 #China 14 #China 15 #Japan 16 17 country='China' 18 class Chinese: 19 20 def __init__(self,name): 21 self.name=name 22 def play_ball(self,ball): 23 print("%s 正在打%s" %(self.name,ball)) 24 p1=Chinese('alex') 25 print(p1.country) #報錯,因為p1調用country在class里面找,找不到不會出去找 26 27 country='China' 28 class Chinese: 29 country='中國' 30 def __init__(self,name): 31 self.name=name 32 print(country) 33 #只是返回一個普通的變量,只有點調用的時候才在類屬性或者實例屬性字典里面去找,所以返回China 34 p1=Chinese('alex') 35 print(p1.country) #這才是調用實例屬性,country才是'中國'
1 class Chinese: 2 country = 'China' 3 def __init__(self,name): 4 self.name=name 5 p1=Chinese('alex') 6 p1.country='Japan' 7 print(Chinese.country) #類屬性沒有變,所以結果還是China 8 9 10 class Chinese: 11 country = 'China' 12 li=['a','b'] 13 def __init__(self,name): 14 self.name=name 15 p1=Chinese('alex') 16 print(p1.li) 17 # p1.li=[666] 18 # print(Chinese.li) #類的列表還是沒變的 19 p1.li.append('cc') #直接改了類里面的列表 20 print(p1.__dict__) 21 print(Chinese.li) #類里面的列表被改變之后,打印出來的里邊當然是新列表['a', 'b', 'cc']
靜態屬性:
1 class Room: 2 def __init__(self,name,owner,width,length,heigh): 3 self.name=name 4 self.owner=owner 5 self.width=width 6 self.length=length 7 self.heigh=heigh 8 @property #在類的普通方法上應用@property裝飾器 9 def cal_area(self): 10 print("%s住的%s總面積是%s" % (self.owner, self.name, self.width * self.heigh * self.length)) 11 r1=Room('豪宅','zy',1000,1000,1000) 12 r2=Room('別墅','zt',1000,1200,1300) 13 r1.cal_area 14 r2.cal_area 15 16 結果: 17 zy住的豪宅總面積是1000000000 18 zt住的別墅總面積是1560000000
類方法:
1 class Room: 2 tag=1 3 def __init__(self,name,owner,width,length,heigh): 4 self.name=name 5 self.owner=owner 6 self.width=width 7 self.length=length 8 self.heigh=heigh 9 @property 10 def cal_area(self): 11 print("%s住的%s總面積是%s" % (self.owner, self.name, self.width * self.heigh * self.length)) 12 def test(self): 13 print('from test',self.name) 14 def tell_info(self): 15 print(self.tag) 16 print(Room.tag) #類可以調用自己的數據屬性 17 r1=Room('wc','alex',10,100,30) #折中方案,必須先實例化,再。。。。 18 Room.tell_info(r1) 19 20 結果:1 1 21 22 優化,類方法: 23 class Room: 24 tag=1 25 def __init__(self,name,owner,width,length,heigh): 26 self.name=name 27 self.owner=owner 28 self.width=width 29 self.length=length 30 self.heigh=heigh 31 @property 32 def cal_area(self): 33 print("%s住的%s總面積是%s" % (self.owner, self.name, self.width * self.heigh * self.length)) 34 def test(self): 35 print('from test',self.name) 36 @classmethod 37 def tell_info(cls): 38 print(cls) 39 print('--->',cls.tag) 40 Room.tell_info() #用類調用類方法,自動傳值,把Room傳給了tell_info 41 42 結果: 43 #<class '__main__.Room'> 44 #---> 1
靜態方法:
1 靜態方法只是類的工具包 2 class Room: 3 tag=1 4 @staticmethod 5 def wash_body(a,b,c): 6 print('%s,%s,%s正在洗澡' %(a,b,c)) 7 Room.wash_body('zy','zt','zc') 8 結果:zy,zt,zc正在洗澡
三:組合(類與類之間沒有共同點,但是有關聯,拼接類使之間能完成某項功能)
1 #組合 2 class School: 3 def __init__(self,name,addr): 4 self.name=name 5 self.addr=addr 6 def zhao_sheng(self): 7 print('%s正在招生' %self.name) 8 class Course: 9 def __init__(self,name,price,period,school): 10 self.name=name 11 self.price=price 12 self.period=period 13 self.school=school 14 15 s1=School('oldboy','beijin') 16 s2=School('oldboy','nanjin') 17 s3=School('oldboy','dongjin') 18 19 c1=Course('linux','10','1h',s1) 20 21 print(c1.__dict__) 22 print(c1.school.name) 23 24 結果: 25 #{'price': '10', 'school': <__main__.School object at 0x00000229CB1EA898>, 'name': 'linux', 'period': '1h'} 26 #oldboy
改進,自己傳值: class School: def __init__(self,name,addr): self.name=name self.addr=addr def zhao_sheng(self): print('%s正在招生' %self.name) class Course: def __init__(self,name,price,period,school): self.name=name self.price=price self.period=period self.school=school s1=School('oldboy','beijin') s2=School('oldboy','nanjin') s3=School('oldboy','dongjin') # c1=Course('linux','10','1h',s1) message=''' 1 oldboy beijin 2 oldboy nanjin 3 oldboy dongjin ''' while True: print(message) menu={ '1':s1, '2':s2, '3':s3 } choice=input('選擇學校:') school_obj=menu[choice] name=input('課程名:') price=input('課程費用:') period=input('課程周期:') new_course=Course(name,price,period,school_obj) print('課程%s屬於%s學校' %(new_course.name,new_course.school.name)) 結果: #1 oldboy beijin #2 oldboy nanjin #3 oldboy dongjin #選擇學校:2 #課程名:linux #課程費用:100 #課程周期:1h #課程linux屬於oldboy學校
四:面向對象編程三大特性
【1】繼承(分:單繼承,多繼承)
1 class Dad: 2 money=10000 3 def __init__(self,name): 4 print('baba') 5 self.name=name 6 def hit_son(self): 7 print('%s 正在打兒子' %self.name) 8 9 class Son(Dad): 10 pass 11 12 s1=Son('zy') 13 print(s1.money) 14 print(s1.__dict__) 15 16 結果: 17 #baba 18 #10000 19 #{'name': 'zy'}

1.當類之間有顯著不同,且較小的類是較大類所需的組件時,用組合比較好。
2.當類之間有很多相同的功能,提取這些共同的功能做成基類,用繼承比較好。

含義一:繼承基類的方法,並且做出自己的改變或者擴展(代碼重用)
含義二:聲明某個子類兼容於某個基類,定義一個接口類,子類繼承接口類,並且實現接口中定義的方法。

接口繼承
接口繼承實際上是要求“做出一個良好的抽象,這個抽象規定了一個兼容接口,使得外部調用者無須關心具體細節,可一視同仁的處理實現了特定接口的所有對象”——這個在程序設計上叫做歸一化。(歸一化使得高層的外部使用者可以不加區分的處理所有的接口兼容的對象集合)
繼承順序:深度優先,廣度優先
(當時經典類時,多繼承情況下,會按照深度優先的方法查找。當時新式類時,會按照廣度優先的方式查找。)
在子類中如何調用父類的方法:
(子類繼承父類的方法,然后想基於原有的基礎上進行修改,那么就需要在子類中調用父類的方法。)
1 class Vehicle: 2 Country='china' 3 def __init__(self,name,speed,load,power): 4 self.name=name 5 self.speed=speed 6 self.load=load 7 self.power=power 8 def run(self): 9 print('開動了') 10 class Subway(Vehicle): 11 def __init__(self,name,speed,load,power,line): 12 Vehicle.__init__(self,name,speed,load,power) 13 self.line = line #子類中派生出的新的方法 14 def show_info(self): 15 print(self.name,self.speed,self.load,self.power,self.line) 16 line13=Subway('北京地鐵','10km/s',10000,'電',13) 17 line13.show_info() 18 line13.run() 19 20 結果: 21 #北京地鐵 10km/s 10000 電 13 22 #開動了
super調用父類方法:

1 class Vehicle: 2 Country='china' 3 def __init__(self,name,speed,load,power): 4 self.name=name 5 self.speed=speed 6 self.load=load 7 self.power=power 8 def run(self): 9 print('開動了') 10 class Subway(Vehicle): 11 def __init__(self,name,speed,load,power,line): 12 # Vehicle.__init__(self,name,speed,load,power) 13 super().__init__(name,speed,load,power) #不用寫父類了,用super調到父類的方法 14 self.line = line #子類中派生出的新的方法 15 def show_info(self): 16 print(self.name,self.speed,self.load,self.power,self.line) 17 line13=Subway('北京地鐵','10km/s',10000,'電',13) 18 line13.show_info() 19 line13.run() 20 21 結果: 22 北京地鐵 10km/s 10000 電 13 23 開動了
【2】多態(多態的概念指出了對象如何通過他們共同的屬性和動作來操作及訪問,而不需要考慮他們具體的類。執行過程中才顯示出多態。)
【3】封裝
(三個層面的封裝,第一,類本身就是一種封裝;第二,類中定義私有的,只在類的內部使用外部無法訪問;第三,明確區分內外,內部的實現邏輯,外部無法知曉,並且為封裝到內部的邏輯提供一個訪問接口給外部使用)
1 class People: 2 __star='earth' 3 def __init__(self,id,name,age,salary): 4 print('--->',self.__star) 5 self.id=id 6 self.name=name 7 self_age=age 8 self._salary=salary 9 def get_id(self): 10 print('這是私有方法,它的id是【%s】' %self.id) 11 #訪問函數,間接訪問 12 def get_star(self): 13 print(self.__star) 14 p1=People('216513548','zy','18',100000000) 15 print(People.__dict__) 16 print(p1._People__star) 17 p1.get_star() 18 結果: 19 #---> earth 20 #{'__module__': '__main__', '__dict__': <attribute '__dict__' of 'People' objects>, '__init__': <function People.__init__ at 0x000001AB8B8248C8>, 'get_star': <function People.get_star at 0x000001AB8B824D08>, '__weakref__': <attribute '__weakref__' of 'People' objects>, '__doc__': None, '_People__star': 'earth', 'get_id': <function People.get_id at 0x000001AB8B824C80>} 21 #earth 22 #earth
1 class Room: 2 def __init__(self,name,owner,width,length,high): 3 self.name=name 4 self.owner=owner 5 self.__width=width #加__后變成私有的,外部訪問不到 6 self.__length=length 7 self.__high=high 8 def tell_area(self): #求面積函數在類class內部,可以訪問長寬高;求面積;等於開了一個接口 9 return self.__width*self.__length*self.__high 10 r1=Room('Bighouse','zy',100,60,90) 11 area=r1.tell_area() #實例化求體積 12 print(area) 13 結果:540000
五:面向對象進階
【1】反射(反射指的是程序可以訪問,檢測和修改它本身狀態或行為的一種能力[自省])
!!!!!python面向對象中的反射:通過字符串的形式操作對象相關的屬性;python中的一切事物都是對象(都可以使用反射)!!!!!
四種可以實現自省的函數:
1.hasattr 2.setattr 3.getattr 4.delattr
1 例子: 2 class Zhongjie: 3 feature='black' 4 def __init__(self,name,addr): 5 self.name=name 6 self.addr=addr 7 def sell_house(self): 8 print('%s正在賣房子'%self.name) 9 def rent_house(self): 10 print('%s正在租房子' %self.name) 11 z1=Zhongjie('sb','jinmao') 12 #對象是否有某種屬性 13 print(hasattr(z1,'name')) #True 14 print(hasattr(z1,'sell_house')) #True 15 print(hasattr(z1,'zyy')) #False 16 #取對象的某種屬性 17 print(getattr(z1,'name')) #sb 18 print(getattr(z1,'rent_house'))#<bound method Zhongjie.rent_house of <__main__.Zhongjie object at 0x0000021A6AA2A780>> 19 print(getattr(z1,'i am a sheep','沒有這個屬性')) #沒有這個屬性,找不到只會返回后面的值,不會報錯 20 #為對象設置某種屬性 21 setattr(z1,'sbb',True) 22 print(z1.__dict__) #{'addr': 'jinmao', 'sbb': True, 'name': 'sb'} 23 #刪除對象某種屬性 24 delattr(z1,'sbb') 25 print(z1.__dict__) #{'name': 'sb', 'addr': 'jinmao'}
!!!!!反射機制的好處:
1 好處一:可以事先定義好接口,接口只有在被完成后才會真正執行,這實現了即插即用,這其實是一種‘后期綁定’,即你可以事先把主要的邏輯寫好(只定義接口),然后后期再去實現接口的功能。 2 好處二:動態導入模塊(基於反射當前模塊成員)
【2】類的內置attr屬性
1. __getattr__ 2. __delattr__ 3.__setattr__
1 實例: 2 #__getattr__ 3 class Foo: 4 x=666 5 def __init__(self,y): 6 self.y=y 7 def __getattr__(self, item): #__getattr__是在調用一個不存在的屬性時才會被執行 8 print('執行__getattr__') 9 f1=Foo(888) 10 print(f1.y) #888 11 print(getattr(f1,'y')) #888 12 f1.zzzzzzz #執行__getattr__ 13 14 #__delattr__ 15 class Foo: 16 x=666 17 def __init__(self,y): 18 self.y=y 19 def __delattr__(self, item): 20 print('刪除操作__delattr__') #刪除的時候會被執行 21 f1=Foo(360) 22 print(f1.y) #360 23 del f1.y #刪除操作__delattr__ 24 del f1.x #刪除操作__delattr__ 25 26 #__setattr__ 27 class Foo: 28 x=666 29 def __init__(self,y): 30 self.y=y 31 def __setattr__(self, key, value): 32 print('__setattr__執行') 33 self.__dict__[key]=value 34 f1=Foo(985) 35 print(f1.__dict__) #__setattr__執行{'y': 985} 36 f1.z=211 #觸發__setattr__ 37 print(f1.__dict__) #__setattr__執行{'z': 211, 'y': 985}
【3】二次加工標准數據類型(包裝標准類型)
包裝:python為大家提供了標准數據類型,以及豐富的內置方法,其實在很多場景下我們都需要基於標准數據類型來定制我們自己的數據類型,新增/改寫方法,這就用到了我們繼承/派生知識
(其他的標准類型均可以通過下面的方式進行二次加工)
1 #包裝標准數據類型 2 class List(list): 3 def append_xixi(self,object): 4 if type(object) is str: 5 super().append(object) 6 else: 7 print('請添加字符串類型數據!!!') 8 9 def show_middle(self): 10 mid_index=int(len(self)/2) 11 return self[mid_index] 12 13 L1=List('i am a beautiful girl') 14 print(L1,type(L1)) #['i', ' ', 'a', 'm', ' ', 'a', ' ', 'b', 'e', 'a', 'u', 't', 'i', 'f', 'u', 'l', ' ', 'g', 'i', 'r', 'l'] <class '__main__.List'> 15 print(L1.show_middle()) #u 16 L1.append_xixi('ojbk') 17 print(L1) #['i', ' ', 'a', 'm', ' ', 'a', ' ', 'b', 'e', 'a', 'u', 't', 'i', 'f', 'u', 'l', ' ', 'g', 'i', 'r', 'l', 'ojbk']
【4】組合的方式完成授權
授權:授權是包裝的一個特性, 包裝一個類型通常是對已存在的類型的一些定制,這種做法可以新建,修改或刪除原有產品的功能。其它的則保持原樣。授權的過程,即是所有更新的功能都是由新類的某部分來處理,但已存在的功能就授權給對象的默認屬性。
實現授權的關鍵點就是覆蓋__getattr__方法
【5】面向對象內置函數的補充:
isinstance(判斷是否是某種數據類型) & issubclass(判斷是否是子類)
(1)__getattribute__
1 class Foo: 2 def __init__(self,x): 3 self.x=x 4 5 def __getattr__(self, item): 6 print('執行的是我') 7 8 def __getattribute__(self, item): 9 print('不管是否存在,都會執行') 10 raise AttributeError('哈哈') 11 12 f1=Foo(10) 13 f1.x 14 f1.xxxxxx 15 #當__getattribute__與__getattr__同時存在,只會執行__getattrbute__,除非__getattribute__在執行過程中拋出異常AttributeError 16 17 結果: 18 #不管是否存在,都會執行 19 #執行的是我 20 #不管是否存在,都會執行 21 #執行的是我
(2)item系列【強調:點.的方式操作屬性就是與attr相關,中括號[]的方式操作屬性就是與item相關】
1 class Foo: 2 def __init__(self,name): 3 self.name=name 4 5 def __getitem__(self, item): 6 print(self.__dict__[item]) 7 8 def __setitem__(self, key, value): 9 self.__dict__[key]=value 10 def __delitem__(self, key): 11 print('del obj[key]時,我執行') 12 self.__dict__.pop(key) 13 def __delattr__(self, item): 14 print('del obj.key時,我執行') 15 self.__dict__.pop(item) 16 17 f1=Foo('sb') 18 f1['age']=18 19 f1['age1']=19 20 del f1.age1 21 del f1['age'] 22 f1['name']='alex' 23 print(f1.__dict__) 24 25 結果: 26 #del obj.key時,我執行 27 #del obj[key]時,我執行 28 #{'name': 'alex'}
(3)__str__與__repr__與__format__ (__str__規定必須return一個值)
1 改變對象的字符串顯示__str__,__repr__ #print觸發的是str,repr是在解釋器中觸發的,都是對輸出進行控制!當print找不到str就是去找repr作為替代品!!! 2 3 class Foo: 4 def __init__(self,name,age): 5 self.name=name 6 self.age=age 7 def __str__(self): 8 return 'my name is %s,and age is %s!' %(self.name,self.age) 9 10 f1=Foo('zy',18) 11 print(f1) #print執行的其實是系統提供的str(F1),所以每次print的時候都是字典字符串,當自己定義__str__后就可以自己控制輸出了 12 13 結果:my name is zy,and age is 18! 14 15 class Foo: 16 def __init__(self,name,age): 17 self.name=name 18 self.age=age 19 def __repr__(self): 20 return 'my name is %s,and age is %s!' %(self.name,self.age) 21 22 f1=Foo('zy',18) 23 print(f1) #repr(f1)觸發——》__repr__() 24 25 結果一樣!!! 26 但是當沒有str就是去找repr作為替代品!!!
1 自定制format: 2 date_dic={ 3 'ymd':'{0.year}:{0.month}:{0.day}', 4 'dmy':'{0.day}/{0.month}/{0.year}', 5 'mdy':'{0.month}-{0.day}-{0.year}', 6 } 7 class Date: 8 def __init__(self,year,month,day): 9 self.year=year 10 self.month=month 11 self.day=day 12 13 def __format__(self, format_spec): 14 if not format_spec or format_spec not in date_dic: 15 format_spec='ymd' 16 fmt=date_dic[format_spec] 17 return fmt.format(self) 18 19 d1=Date(2016,12,29) 20 print(format(d1)) 21 print('{:mdy}'.format(d1)) 22 23 結果: 24 #2016:12:29 25 #12-29-2016
(4)__slots__屬性:

1.__slots__是什么:是一個類變量,變量值可以是列表,元祖,或者可迭代對象,也可以是一個字符串(意味着所有實例只有一個數據屬性)。 2.引子:使用點來訪問屬性本質就是在訪問類或者對象的__dict__屬性字典(類的字典是共享的,而每個實例的是獨立的)。 3.為何使用__slots__:字典會占用大量內存,如果你有一個屬性很少的類,但是有很多實例,為了節省內存可以使用__slots__取代實例的__dict__。 當你定義__slots__后,__slots__就會為實例使用一種更加緊湊的內部表示。實例通過一個很小的固定大小的數組來構建,而不是為每個實例定義一個字典,這跟元組或列表很類似。在__slots__中列出的屬性名在內部被映射到這個數組的指定小標上。使用__slots__一個不好的地方就是我們不能再給實例添加新的屬性了,只能使用在__slots__中定義的那些屬性名。 4.注意事項:__slots__的很多特性都依賴於普通的基於字典的實現。另外,定義__slots__后的類不再支持一些普通類特性了,比如多繼承。大多數情況下,你應該只在那些經常被使用到的用作數據結構的類上定義__slots__比如在程序中需要創建某個類的幾百萬個實例對象 ,關於__slots__的一個常見誤區是它可以作為一個封裝工具來防止用戶給實例增加新的屬性。盡管使用__slots__可以達到這樣的目的,但是這個並不是它的初衷。更多的是用來作為一個內存優化工具。
1 class Foo: 2 __slots__ = ['name','age'] #定義在類當中的類屬性,使之不在具有__dict__字典 3 f1=Foo() 4 f1.name='zy' 5 f1.age=18 6 print(f1.name) 7 print(f1.age) 8 print(f1.__slots__) #幫助省內存 9 10 結果: 11 #zy 12 #18 13 #['name', 'age']
(5)doc屬性
1 class Foo: 2 '我是描述信息' 3 pass 4 class Bar(Foo): 5 pass 6 print(Bar.__doc__) #該屬性無法繼承給子類 7 #原理就是在每一個類當中都會加一個__doc__,之要調就有 8 9 結果:None
(6)__module__與__class__
1 __module__ 表示當前操作的對象在那個模塊 2 __class__ 表示當前操作的對象的類是什么
(7)__del__析構方法
1 析構方法,當對象在內存中被釋放時,自動觸發執行。 2 #注:如果產生的對象僅僅只是python程序級別的(用戶級),那么無需定義__del__,如果產生的對象的同時還會向操作系統發起系統調用,即一個對象有用戶級與內核級兩種資源,比如(打開一個文件,創建一個數據庫鏈接),則必須在清除對象的同時回收系統資源,這就用到了__del__ 3 4 class Foo: 5 def __init__(self,name): 6 self.name=name 7 def __del__(self): 8 print('我執行了') 9 f1=Foo('zy') 10 del f1 11 print('ennnn') 12 #結果:我執行了 13 # ennnn 14 15 但是: 16 class Foo: 17 def __init__(self,name): 18 self.name=name 19 def __del__(self): 20 print('我執行了') 21 f1=Foo('zy') 22 #del f1 23 print('ennnn') 24 #結果:ennnn 25 # 我執行了
(8)__call__
1 class Foo: 2 def __call__(self, *args, **kwargs): 3 print('實例執行了') 4 f1=Foo() # 5 f1() #調用Foo類下的__call__ 6 結果:實例執行了
(9)__next__與__iter__實現迭代器協議
1 class Foo: 2 pass 3 f1=Foo() 4 for i in f1: #因為f1是對象所以可以for循環 5 print(i) 6 #但是:TypeError: 'Foo' object is not iterable 報錯說Foo不是可迭代的對象 7 #怎么實現可迭代呢??? 8 class Foo: 9 def __init__(self,n): 10 self.n=n 11 def __iter__(self): 12 return self 13 def __next__(self): 14 self.n+=1 15 return self.n 16 f1=Foo(1) 17 print(f1.__next__()) 18 for i in f1: #for其實就是f1實現__iter__方法,迭代器,實際就是iter(f1)——》f1.__iter__ 19 print(i) 20 21 結果:無限加1 22 23 拋出異常,使之停止一直循環 24 class Foo: 25 def __init__(self,n): 26 self.n=n 27 def __iter__(self): 28 return self 29 def __next__(self): 30 if self.n==12: 31 raise StopIteration('停止') 32 self.n+=1 33 return self.n 34 f1=Foo(1) 35 print(f1.__next__()) 36 for i in f1: #for其實就是f1實現__iter__方法,迭代器,實際就是iter(f1)——》f1.__iter__ 37 print(i) 38 39 結果:2----12
1 利用迭代器實現的裴波那契序列: 2 class Fib: 3 def __init__(self): 4 self._a=1 5 self._b=1 6 def __iter__(self): 7 return self 8 def __next__(self): 9 if self._a>100: 10 raise StopIteration('停了') 11 self._a,self._b=self._b,self._a+self._b 12 return self._a 13 f1=Fib() 14 print(f1.__next__()) 15 for i in f1: 16 print(i) 17 18 結果:1----114