Python 3學習 ——面向對象
Python 學習——面向對象
寫此博客 是為了激勵自己,並且將自己的心得以及遇到的問題與人分享
一、面向對象基礎
面向對象就是一個類和對象的應用。
1.定義方法:
----------------------------------------------------------------
class 類名:
def 方法名(self , arg):
print(arg)
中間人 = 類名()
中間人.方法名(arg)
----------------------------------------------------------------
self 代指,調用方法的 對象 (中間人)
2.構造方法:類名加()自動執行構造方法
1 class Person: 2 def __init__(self,name,age): 3 self.n = name 4 self.a = age 5 def show(self): 6 print("%s %s " %(self.n,self.a)) 7 8 liufeiduo = Person(‘劉飛鐸‘,19) 9 liufeiduo.show() 10 11 chengjunfei = Person(‘程俊飛‘,18) 12 chengjunfei.show()
3.繼承
1 class Father: # 父類,基類 2 def 籃球(self): 3 pass 4 def 足球(self): 5 pass 6 def 抽煙(self): 7 pass 8 9 class Son(Father): # 子類,派生類 10 def 排球(self): 11 pass 12 13 14 s = Son() 15 s.籃球()
子類重寫父類方法
1 classF: 2 def f1(self): 3 print(‘F,f1‘) 4 def f2(self): 5 print(‘F,f2‘) 6 7 class S(F): 8 def s1(self): 9 print(‘S,s1‘) 10 def f2(self): 11 print(‘S,s2‘) 12 13 obj = S() 14 obj.s1() #S,s1 s1中的self 是形參,此時代指 obj 15 obj.f2() #S,s2
self 永遠指調用方法的調用者
兩種調用父類的方法:
方法一: super
class F: def f1(self): print(‘F,f1‘) def f2(self): print(‘F,f2‘) class S(F): def s1(self): print(‘S,s1‘) def f2(self): super(S,self).f2() #執行父類中的f2方法 #super代指了它的父類 print(‘S,s2‘) obj = S() obj.f2() ‘‘‘ F,f2 S,s2 ‘‘‘
方法二:通過父類名調用方法
class F: def f1(self): print(‘F,f1‘) def f2(self): print(‘F,f2‘) class S(F): def s1(self): print(‘S,s1‘) def f2(self): #super(S,self).f2() #執行父類中的f2方法 #super代指了它的父類 print(‘S,s2‘) F.f2(self) obj = S() obj.f2() ‘‘‘ S,s2 F,f2 ‘‘‘
多繼承:Python 與 C++ 獨有支持多繼承,一個子類可以繼承多個父類。
1 class F1: 2 def a(self): 3 print(‘F1.a‘) 4 5 class F2: 6 def a(self): 7 print(‘F2.a‘) 8 9 class Son(F1,F2): # 按照從左到右的順序,"一條路找到黑的順序"來進行找。 如果有同一個根時,根最後執行。 10 pass 11 12 obj = Son() 13 obj.a() #F1.a
4.多態
1 def func(arg): 2 print(arg) 3 # Python 中的原生多態,不被類型所限定。 4 func(1) 5 6 func(‘llalala‘)
二、面向對象中級
1.類成員
字段
普通字段,保存在對象中,執行只能通過對象訪問。
靜態字段,保存在類中,在內存中只保存一份,執行時可以通過對象訪問也可以通過類進行訪問。
1 class Provience: 2 country = ‘中國‘ 3 4 def __init__(self,name): 5 self.name = name 6 henan = Provience(‘河南‘) 7 print(Provience.country) #中國 8 print(henan.name) #河南
方法
普通方法,保存在類中,由對象來進行調用。self --> 對象
靜態方法,保存在類中,由類直接調用。
類方法,保存在類中,由類直接調用。cls --> 當前類
1 class Foo: 2 3 def bar(self): #普通方法 4 print(‘bar‘) 5 6 @staticmethod 7 def sta(a1,a2): #靜態方法 self 就不是必須存在的了 8 print(a1,a2) 9 10 @classmethod 11 def classmd(cls): #類方法 cls 是類名 不依賴對象 可以通過類直接執行 12 print(cls) 13 print(‘classmd‘) 14 15 object = Foo() 16 object.bar() #bar 17 18 Foo.sta(2,4) #2 4 調用者直接類調用就可以了 19 20 Foo.classmd() # <class ‘__main__.Foo‘> classmd
應用場景:
如果對象中需要保存一些值,執行某功能時,需要使用對象中的值 ---> 普通方法。
不需要任何對象中的值 ---> 靜態方法。
類的成員——屬性:按照方法的方式寫,按照字段調用的方式調用。
1 class Foo: 2 def __init__(self): 3 self.name = ‘a‘ 4 5 def bar(self): 6 print(‘bar‘) 7 8 @property #通過property裝飾器 9 def per(self): # 屬性: 偽造成方法,但訪問的時候使用的是字段的方式 10 print(‘per‘) 11 12 obj = Foo() 13 obj.per
利用 屬性 完成分頁的功能:
class Pergination: def __init__(self,current_page): self.page = int(current_page) @property def start(self): val = (self.page - 1) * 10 return val @property def end(self): val = self.page * 10 return val li = [] for i in range(1000): li.append(i) while True: p = input(‘請輸入要查看的頁碼: ‘)# 每頁顯示十條 obj = Pergination(p) print(li[obj.start:obj.end])
三、面向對象高級
1. 成員修飾符
公有成員
私有成員 __字段名
- 無法直接訪問,只能間接訪問
- 繼承過來的私有字段是無法進行訪問,內部訪問指的是自身內部,繼承過來的不可以。
私有字段
1 class Foo: 2 3 def __init__(self,name,age): 4 self.name = name 5 # self.age = age 6 self.__age = age # 私有,外部無法直接進行訪問 7 8 def show(self): #間接訪問私有字段方法 9 return self.__age 10 11 obj = Foo(‘chengjunfei‘,20) 12 print(obj.name) 13 print(obj.show()) #間接訪問私有字段
2. 特殊成員
__init__ 類() 自動執行
__call__ 對象() 類()()自動執行
1 class Foo: 2 3 def __init__(self): 4 print(‘init‘) 5 6 def __call__(self,*args,**kwargs): 7 print(‘call‘) 8 9 10 11 Foo()() #init call 12 13 object = Foo() 14 object() #對象後面加括號會執行 __call__ 中的方法,Python的一個內置語法。
__int__ int(對象)
__str__ str(對象)
__add__
1 class Foo: 2 def __init__(self): 3 pass 4 5 def __add__(self, other): 6 return 123 7 8 obj1 = Foo() 9 obj2 = Foo() 10 11 r = obj1 + obj2 12 # 兩個對象相加時,自動執行第一個對象的__add__方法,並且將第二個對象當作參數傳遞進去。 13 14 print(r,type(r)) #123 <class ‘int‘>
__del__ 析構方法,當對象被銷毀時,自動執行。
__dict__ 將對象中封裝的所有內容通過字典的形式返回。
1 class Foo: 2 3 def __init__(self,name,age): 4 self.name = name 5 self.age = age 6 7 object = Foo(‘劉飛鐸‘,21) 8 9 d = object.__dict__ 10 print(d) #{‘name‘: ‘劉飛鐸‘, ‘age‘: 21} 11 12 c = Foo.__dict__ 13 print(c) #{‘__module__‘: ‘__main__‘, ‘__init__‘: <function Foo.__init__ at 0x0000016D6A1499D8>, 14 # ‘__dict__‘: <attribute ‘__dict__‘ of ‘Foo‘ objects>, ‘__weakref__‘: <attribute ‘__weakref__‘ of ‘Foo‘ objects>, 15 # ‘__doc__‘: None}
__getitem__ # 切片(slice類型)或者索引 有返回值
__setitem__ 沒有返回值
__delitem__ 沒有返回值
1 class Foo: 2 3 def __init__(self,name,age): 4 self.name = name 5 self.age = age 6 7 def __getitem__(self, item): 8 return item + 10 9 10 def __setitem__(self, key, value): 11 print(key) 12 print(value) 13 14 def __delitem__(self, key): 15 print(key) 16 17 18 li = Foo(‘Liufeiduo‘,22) 19 r = li[8] #自動執行li對象中的__getitem__方法,8當作參數傳遞給了item 20 21 print(r) #18 22 23 li[100] = ‘asdf‘ # def __setitem__(self, key, value): 24 del li[985] # def __delitem__(self, key):
__iter__ :如果類中有 __iter__ 方法,對象 ---> 可叠代對象。
對象.__iter__ ()的返回值,就是叠代器。
for 循環 遇到 叠代器,就執行 next( ) 方法就行了。
for 循環 遇到 可叠代對象,要先通過 可叠代對象.__iter__ ( )方法獲取叠代器然後繼續執行next( )方法。
1 class Foo: 2 3 def __init__(self,name,age): 4 self.name = name 5 self.age = age 6 def __iter__(self): 7 return iter([11,22,33,44]) 8 9 li = Foo(‘liufeiduo‘,22) 10 #1.獲取li對象的類 Foo 中的__iter__ 方法,並獲取其返回值。 11 #2.去循環上一步中返回的對象。 12 for i in li: 13 print(i) # 11/r 22/r 33/r 44/r
3. metaclass 類的祖宗
a. 在Python中,一切事物都是對象。
b.
class Foo():
pass
obj = Foo()
# obj 是對象,Foo 是類。
# Foo 類也是一個對象,type 的對象。
c. 類都是 type 類的對象 type(...)
"對象"都是類的對象 類()
1 class MyType(type): 2 def __init__(self,*args,**kwargs): 3 print(‘123‘) 4 pass 5 6 7 class Foo(object,metaclass=MyType): 8 def func(self): 9 print(‘hello‘) 10 11 # 執行結果: 123
類後面加括號,創建對象並不是直接執行了該類的 __init__ 方法,先執行 type 的 __call__ 方法,再執行該類的 __new__ 方法,再然後執行了 __init__ 方法。
4. 異常處理
1 #-----------------最基本的--------------------- 2 while True: 3 try: 4 inp = input(‘請輸入序號:‘) 5 # 代碼塊,邏輯 6 i = int(inp) 7 except Exception as e: 8 # e 是Exception的對象,對象中封裝了錯誤信息。 9 # 上述代碼塊出錯,自動執行當前塊內容。 10 print(e) 11 i = 1 12 13 print(i) 14 15 #--------------寫異常的基本流程-------------------------------- 16 try: 17 int (‘w3rs‘) 18 except IndexError as e: 19 print(‘IndexError‘,e) 20 except ValueError as e: 21 print(‘ValueError‘,e) 22 except Exception as e: 23 print(‘Exception‘,e) 24 25 else: 26 print(‘else‘) 27 28 finally: 29 print(‘....‘) 30 #--------------------------------------------
寫異常時,先 except ‘小弟’,後寫‘大哥’,else 後面是沒有捕捉到錯誤時執行,finally 後是無論如何都會執行。
主動拋出異常
1 try: 2 raise Exception(‘我是主動拋出的異常‘) # 主動觸發異常 3 except Exception as e: 4 print(e) 5 # 執行結果:我是主動拋出的異常
主動觸發異常的小應用(記錄錯誤日誌)
1 def db(): 2 #return True 3 return False 4 5 def index(): 6 try: 7 result = db() 8 if not result: 9 #打開文件,寫日誌 10 raise Exception(‘數據庫處理錯誤‘) #當數據庫返回值為False時,主動拋出異常,記錄日誌。 11 12 except Exception as e: 13 str_error = str(e) 14 print(str_error) 15 #打開文件寫日誌 16 17 index()
自定義異常
1 class LfdError(Exception): 2 3 def __init__(self,msg): 4 self.message = msg 5 6 def __str__(self): 7 return self.message 8 9 obj = LfdError(‘liufeiduo‘) 10 print(obj) 11 12 try: 13 raise LfdError(‘我錯了‘) 14 except LfdError as e: 15 print(e)
斷言 assert + 條件 如果滿足條件,繼續執行,若不滿足條件,直接報錯。用於強制用戶服從,不服從就報錯,可捕獲但一般不捕獲。
5. 反射
在Python 中執行反射效率蠻高的。
通過字符串的形式操作對象中的成員:
①getattr方法,到某某東西中獲取某某內容。
1 class Foo: 2 def __init__(self,name,age): 3 self.name = name 4 self.age = age 5 6 def show(self): 7 return "%s-%s" %(self.name,self.age) 8 object = Foo(‘liufeiduo‘,22) 9 10 # b = "name" 11 # print(object.__dict__[b]) 12 inp = input(‘>>>>>>>>>>‘) 13 #去什麽東西裏面獲取什麽內容 14 b = getattr(object,inp) 15 16 print(b) #liufeiduo
②hasattr方法,去檢測對象中是否有某成員,返回True、False。
③setattr方法,在對象中主動設置某個值。
1 class Foo: 2 def __init__(self,name,age): 3 self.name = name 4 self.age = age 5 6 def show(self): 7 return "%s-%s" %(self.name,self.age) 8 object = Foo(‘liufeiduo‘,22) 9 10 11 setattr(object,‘love‘,‘chengjunfei‘) 12 print(object.love) #chengjunfei
④delattr方法,將主動設置的某個值刪除掉。
反射在模塊之間也是可以用的。
6.單例模式
class Foo: __v = None @classmethod def get_instance(cls): if cls.__v: return cls.__v else: cls.__v = Foo() return cls.__v object1 = Foo.get_instance() print(object1) object2 = Foo.get_instance() print(object2) # 執行結果: #<__main__.Foo object at 0x000001137E007908> #<__main__.Foo object at 0x000001137E007908>
好處:內存中對象只創建一份就可以了,
Python 3學習 ——面向對象