python09-面向對象(二) & 異常

面向對象

  • 回顧:

    • 反射:以字符串的形式去某個對象(模塊,類,對象)操作它的成員(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
# 如果為真,則真
# 如果為假,則拋異常
# 做測試用,限制軟件的運行環境等
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容