1. 程式人生 > >12-python基礎知識-面向物件

12-python基礎知識-面向物件

面向物件

抽象基類(瞭解)

  • 說明:

    • 抽象基類就是為了統一介面而存在的
    • 抽象類不能進行例項化(建立物件)
    • 繼承自抽象類的子類必須實現抽象類中的抽象方法
  • 示例:

    from abc import ABC, abstractmethod
    
    # 抽象基類
    class Animal(ABC):
        # 定義抽象方法:規定介面
        @abstractmethod
        def run(self):
            pass     
        
        
    # 抽象基類無法例項化  
    # a = Animal()
    class Cat(Animal): # 子類中必須實現抽象基類的抽象方法,才能例項化 def run(self): print('貓喜歡走貓步') c = Cat()

特殊函式

  • 示例1

    d = {'name': 'xiaoming', 'age': 20}
    
    # 返回物件的字串表示形式
    r = repr(d)
    
    print(r, type(r))
    
    # 執行有效的python程式碼字串
    d2 = eval(r)
    
    print(d2, type(d2))
    
    a = 10
    b = 20
    c = eval
    ('a + b') print(c)
  • 示例2:

    class Person:
        def __init__(self, name, age):
            self.name = name
            self.age = age
    
        # print列印物件,str方法轉換時都會觸發
        def __str__(self):
            print('__str__')
            return '姓名:{} 年齡:{}'.format(self.name, self.age)
    
        # 返回物件的字串表示形式,使用repr函式處理時會自動觸發
        def
    __repr__(self): return "Person('{}', {})".format(self.name, self.age) p = Person('王大花', 18) # print(p) # s = str(p) r = repr(p) print(r) p2 = eval(r) print(p2, type(p2))

內建方法

  • 構造和析構

    __init__、__del____
    
  • 干預屬性操作

    __setattr__、__getattr__、__delattr__
    
  • 支援字典操作

    __setitem__、__getitem__、__delitem__
    
  • 物件支援函式呼叫

    __call__
    
  • 列印輸出或str轉換

    __str__
    
  • 物件的字串表示,呼叫repr方法時觸發

    __repr__
    

運算子過載

  • 算術運算子

    • 示例:
    class Number:
        def __init__(self, num):
            self.num = num
    
        # 物件出現在'+'的左邊時會自動觸發
        def __add__(self, other):
            print('__add__')
            return self.num + other
    
        # 物件出現在'+'的右邊時會自動觸發
        def __radd__(self, other):
            print('__radd__')
            return self.num + other
    
        # +=運算時自動觸發,若沒有實現會呼叫__add__
        def __iadd__(self, other):
            print('__iadd__')
            # 返回新的Number物件
            # return Number(self.num + other)
            # 返回處理後的原始物件
            self.num += other
            return self
        
    n = Number(10)
    print(id(n))
    
    # ret = n + 20
    # ret = 20 + n
    # print(ret)
    
    n += 50 # n = n + 50
    print(id(n))
     
    
    • 自行測試
    加法:add、radd、iadd
    減法:sub、rsub、isub
    乘法:mul、rmul、imul
    除法:truediv、rtruediv、itruediv
    求餘:mod、rmod、imod
    
  • 關係運算符

    class Number:
          def __init__(self, num):
              self.num = num
    
          # 大於 >
          def __gt__(self, other):
              print('__gt__')
              return self.num > other
    
          # 小於 <
          def __lt__(self, other):
              print('__lt__')
              return self.num < other
    
          # 等於 ==, 判斷是否相等,當不實現__ne__時,!=運算也會觸發
          def __eq__(self, other):
              print('__eq__')
              return self.num == other
    
          # 大於等於 >=
          def __ge__(self, other):
              print('__ge__')
              return self.num >= other
    
          # 小於等於 <=
          def __le__(self, other):
              print('__le__')
              return self.num <= other
    
          # 不等於 !=
          def __ne__(self, other):
              print('__ne__')
              return self.num != other
            
    n = Number(20)
    
    print(n > 10)
    print(n < 10)
    print(n == 10)
    print(n != 10)        
    

記憶體管理

  • 引用計數

    • python中所有的資料都是通過類來實現的,物件的管理是通過引用計數實現的
    • 當建立一個物件賦值給一個變數時,引用計數為1,當多一個變數指向該物件時,計數值加1;當少一個變數指向物件時,計數值減1。計數值減到0時會呼叫__del__方法釋放儲存空間
    • 不可變變數引用計數是沒有意義的
    • 示例:
    import sys
    
      # 不可變變數的引用計數沒有意義
      a = 10
      print(sys.getrefcount(a))
    
      lt = [1, 2, 3]
      lt2 = lt
      # 本身此時引用計數為1,但是該方法也引用了一次
      print(sys.getrefcount(lt))
      del lt2
      print(sys.getrefcount(lt))
        
    class Person:
        def __del__(self):
            print('物件即將釋放')
            
    p = Person()
    print(sys.getrefcount(p))
    del p
    print('over')          
    
  • 函式傳參

    • 對不可變變數來說,傳遞的是值,函式中不可能改變傳遞的引數
    • 對於可變變數及自定義的類建立的物件,傳遞的是引用,函式中可以操作原物件
    • 示例:
    def test(a):
    	a += 1
    
    num = 100
    # 對於不可變資料傳遞的是值
    
    test(num)
    	print(num)
    
    def test2(lt):
    lt[0] = 10
    
    lt = [1, 2, 3]
    test2(lt)
    print(lt)    
    
  • 深淺拷貝

    import copy
    
    lt = [1, 2, [3, 4]]
    # 賦值會增加一個引用,訪問的都是同一資料
    
    lt2 = lt
    # 淺拷貝:只拷貝物件本身,裡面的元素只會增加一個引用
    # lt2 = lt.copy()
    
    # 專門的拷貝函式,也是淺拷貝,等價於上面的拷貝
    lt2 = copy.copy(lt)
    
    # 深拷貝:拷貝物件本身,物件中的元素也進行拷貝
    # lt2 = copy.deepcopy(lt)
    
    lt[0] = 100
    lt2 = 30
    
    print(lt)
    print(lt2)
    print(id(lt))
    print(id(lt2))
    
    # 判斷是否是同一物件的多個引用
    print(lt is lt2)
    

資料持久化儲存

  • 說明:持久化儲存方案,普通檔案、資料庫、序列化

  • 示例:

    import pickle
    
    class Person:
        def __init__(self, name, age):
            self.name = name
            self.age = age
    
        def __str__(self):
            return 'name:{} age:{}'.format(self.name, self.age)
       
       
    xiaoming = Person('xiaoming', 20)
    # print(xiaoming)
    
    # 序列化:會將物件轉換為bytes
    # s = pickle.dumps(xiaoming)
    # print(s)
    
    # 反序列化:從bytes中解析出物件
    # xm = pickle.loads(s)
    # print(xm, type(xm)) 
    
    # 直接儲存到檔案
    # fp = open('data.txt', 'wb')
    # pickle.dump(xiaoming, fp)
    # fp.close()
    
    # 從檔案中讀取物件
    fp = open('data.txt', 'rb')
    xm = pickle.load(fp)
    print(xm, type(xm))