面向對象
-
回顧:
- 反射:以字符串的形式去某個對象(模塊,類,對象)操作它的成員(python中,一切皆對象)
# 從模塊中獲取屬性 module = __import__('commons') # 引入commons模塊 if __name__ == '__main__': if hasattr(module, 'f1'): # print('ok') f1 = getattr(module, 'f1') ret = f1() print('ret =', ret) # 從類中獲取屬性 class Cat: desc = 'YHH' def __init__(self, name): self.name = name def show(self): print(self.name) show = getattr(Cat, 'show') show(Cat('yhh')) # 從對象中獲取屬性 cat = Cat('yhh') show = getattr(cat, 'show') show()
- 多繼承面試題:
# 繼承關系: # A(ooo) --> D # B(ooo) --> C(xxx,ooo) --> D class D(A,C): pass dog = D() # 創建D實例 dog.xxx() # 調用xxx方法,只有C有,調用C的 # 在xxx方法內部調用ooo方法,雖然C也有ooo方法 # 但是函數內部調用方式為:self.ooo() # 根據繼承的調用順序,雖有調用的是A的ooo方法 # 看別人的代碼時,驚顫遇到這個問題--方法由誰發起的就由誰開始找
- 繼承中調用構造方法
- 創建對象時會調用對象的__init__方法
- 如果對象沒有__init__方法,回去調用父類的構造方法
class Animal: def __init__(self): print('Animal') class Cat(Animal): def __init__(self): print('Cat') cat = Cat() # Cat # ===================== class Animal: def __init__(self): print('Animal') class Cat(Animal): # def __init__(self): # print('Cat') pass cat = Cat() # Animal
- 調用父類的構造方法
- 調用父類的構造方法有兩種方式:
# 一:第一個參數為當前類,第二個參數為self # 表示找到Cat的父類并執行構造方法 class Animal: def __init__(self): print('Animal') class Cat(Animal): def __init__(self): print('Cat') super(Cat, self).__init__() cat = Cat() # Cat Animal # 二:主動去調用父類的構造方法 class Animal: def __init__(self): print('Animal') class Cat(Animal): def __init__(self): print('Cat') Animal.__init__(self) cat = Cat() # Cat Animal
-
成員:
- 反射:
- 通過類-對象指針也能找到類中的方法
class Cat(): def __init__(self, name): self.name = name def show(self): print(self.name) cat = Cat('yhh') ret = hasattr(Cat, 'show') # 類中的方法 print(ret) # True ret = hasattr(cat, 'name') # 對象的屬性 print(ret) # True ret = hasattr(cat, 'show') # 對象的方法 print(ret) # True
- 手動實現從導入模塊到創建對象再獲取對象屬性的反射
module = __import__('commons', fromlist=True) class_name = getattr(module, 'Cat') cat = class_name('yhh') name = getattr(cat, 'name') print(name) # yhh method = getattr(cat, 'show') method()
-
靜態字段:靜態字段存在類中
- 如果一個類中所有的對象都用共同的字段且想通過,可將此字段設置為靜態字段
- 在類中存在的字段為靜態字段,在對象中存在的字段為普通字段
class Province: country = 'China' # 靜態字段
-
類的成員:普通字段,普通方法,靜態字段,靜態方法,類方法,特性
- 約定俗成:普通字段,普通方法由對象訪問,靜態字段,靜態方法,類方法由類訪問
- 通過類訪問普通方法需要參數需要傳入對象
靜態方法
class Cat: @staticmethod def show(): pass
- 類方法
- 類方法其實相當于靜態方法的另一種形式,只是調用時python自動將類名傳給方法
class Cat: @classmethod def show(cls): print(cls) Cat.show()
-
特性(屬性)
- 執行方法一般為對象名.方法名()來調用,如果在定義方法的時候加上@property,那么調用該方法是不需要加上括號(前提是該方法不需要參數)
- 當方法名和字段名相同,寫在后面的會覆蓋前面的,一般不會這么寫
- 作用:把方法偽造成字段來操作(比較雞肋)
class Cat: def __init__(self, name): self.name = name @property def show(self): print(self.name) cat = Cat('yhh') cat.show cat.name # 獲取字段 cat.name = 'newName' # 修改字段 cat.show # 通過特性,以字段的形式調用函數 cat.show = 'haha' # 報錯 # 如果想要不報錯,則修改代碼 class Cat: def __init__(self, name): self.name = name @property def show(self): print(self.name) @show.setter def show(self,arg): self.name = arg cat = Cat('yhh') cat.show cat.show = 'catName' cat.show # 定義一個和@property方法名一樣的方法,方法加上@方法名.setter就可以使得方法可以像修改屬性一樣傳遞參數
- 反射:
-
修飾符:
- 在方法或者字段前加上__表示私有
- 私有的方法和屬性不能被繼承,只有自己能夠訪問
- 私有也可以獲取:
- python中有個特殊的方法,私有的實行和方法也可以獲取,一般不會這么用
class Cat: __xo = 'xo' def __show(self): print('show') def pub(self): self.__show() cat = Cat() print(cat._Cat__xo) # 對象._類名__屬性名或方法
-
特殊方法:
- __init__:構造方法,創建對象的時候調用
- __del__:解析器銷毀對象的時候調用
- __call__:當調用對象名()的時候調用
- Django,web框架的源碼用到
class Cat: def __init__(self): print('創建對象的時候調用') def __call__(self, *args, **kwargs): print('對象名()調用') cat = Cat() # 調用構造方法 cat() # 調用call方法
- __setitem__,__getitem__,__delitem__
- 自定義section會用到
- __str__
li = list([11, 22, 33, 44]) # ls是一個對象 print(li[1]) # 對象名[index] li[1] = 'index' # 對象名[index] = value del li[1] # del 對象名[index] print(li) # 打印對象 print(str(li)) # str(對象名) # li是list類的一個對象,通過類似的,我們自己創建的一個對象 class Cat: def __getitem__(self, item): print('getitem', item) def __setitem__(self, key, value): print('setitem', key, value) def __delitem__(self, key): print('delitem', key) cat = Cat() cat[1] # getitem 1 cat['k1'] # getitem k1 cat['key'] = 'value' # setitem key value del cat['key'] # delitem key # 通過切片時: cat = Cat() cat[1:2:3] # getitem slice(1, 2, 3) cat[1:2:3] = 123 # setitem slice(1, 2, 3) 123 del cat[1:2:3] # delitem slice(1, 2, 3) # python2.7中操作切片時會調用: # __getslice__ # __setslice__ # __delslice__ # 在python3.x中會調用: # __getitem__ # __setitem__ # __delitem__ #========================== # 直接打印對象會調用對象的__str__() # 將對象轉字符串也會調用__str__() class Cat: def __str__(self): return '調用str方法' cat = Cat() print(cat) print(str(cat))
- dict:查看成員(比較重要)
- 應用:自定義form框架的時候用
- 獲取對象里面所有的字段
class Cat: def __init__(self, name): self.name = name def show(self): pass def fun(self): pass ret = Cat.__dict__ print(ret)# {'__module__': '__main__', 'fun': <function Cat.fun at 0x102173ae8>, 'show': <function Cat.show at 0x102173a60>, '__weakref__': <attribute '__weakref__' of 'Cat' objects>, '__dict__': <attribute '__dict__' of 'Cat' objects>, '__init__': <function Cat.__init__ at 0x1021739d8>, '__doc__': None} obj = Cat('yhh') ret = obj.__dict__ print(ret) # {'name': 'yhh'}
- iter:
- for循環對象時會調用__iter__方法
li = list([11, 22, 33, 44, 55]) for item in li: print(item) # li是list類的對象,for循環li對象時會遍歷得到結果 # 自定義對象遍歷: class Cat: def __iter__(self): yield 11 yield 22 yield 33 yield 44 cat = Cat() for item in cat: print(item)
-
__new__ & __metaclass__
- python中一切皆對象,類是對象,模塊是對象,類創建的也是對象
- 解析器解析到class關鍵字就會創建類對象(默認由type創建)
class Cat: __metaclass__ = xxx # 表示由xxx來創建這個類 # 創建類: Cat = type(Cat, (object,),{"fun1":func} # type(類名,(基類,..),{成員})
異常
- 編程難免遇到報錯,如web網頁盡量避免大黃頁,應該讓用戶看到有好的錯誤頁面.
try:
# 需要保護的代碼
li = [11, 2, 3]
ret = li[5]
except IndexError as IE:
# 遇到異常時執行的代碼塊
print(IE)
except Exception as e:
# 遇到異常時執行的代碼塊
print(type(e))
else:
# 沒有異常時執行的代碼塊
print('no exception')
finally:
# 不管有沒有異常都會執行的代碼塊
print('finally')
- 異常分類:
- 所有異常都是Exception的派生類
- 主動觸發異常
raise Exception('異常')
try:
raise Exception('發生異常')
except Exception as e:
pass
- 斷(意義不大)
assert 1 == 1
assert 2 == 1
# 如果為真,則真
# 如果為假,則拋異常
# 做測試用,限制軟件的運行環境等