python中面向對象相關知識點(全面總結筆記)

面向對象

  • 與面向過程對比:
    • 面向過程:數學邏輯的映射,學會做個好員工
    • 面向對象:生活邏輯的映射,學會做個好領導
  • 官方定義:
    • 類:具有相同特徵(屬性和行爲)的事物的抽象
    • 對象:某個類的具象
  • 編程語言:
    • 類:是一種自定義的數據類型
    • 對象:某個類類型的變量

面向對象語法

  • 類的定義:
    class 類名:
    內容

  • 語法說明:

    • 定義類需要使用關鍵字class
    • 類名:原則上只要符合標識符命名規範即可,但是通常我們都使用大駝峯(每個單詞首字母大寫)風格命名
      • 如:UserName
    • 類名後面的’:'不要忘記
    • 類的內容要進行整體縮進
    • 行爲:通過方法體現,在類中定義相關的函數即可(第一個參數通常是self)
    • 屬性:通過變量體現,在需要時動態添加,很多時候定義類時沒有體現
    • 成員訪問:
      • 屬性:對象.屬性名
      • 方法:對象.方法名()
  • 示例:
    # 定義類
    class Person:
    # 行爲通過方法體現

        # 吃飯
        def eat(self):
            print('紅燒雞腿我喜歡吃')
    
        # 睡覺
        def sleep(self):
            print('睡覺也是一種生活態度')
            
    # 定義對象
    liang = Person()
    # 調用方法
    liang.eat()
    liang.sleep()
    # 屬性時動態添加的
    liang.name = '某某某'
    # 獲取屬性
    print(liang.name)
    
  • self使用
    class Person:
    def run(self):
    # self表示當前對象:誰調用該方法就表示誰
    print(’{}每天以2m/s的速度慢跑5km’.format(self.name))

        def introduce(self):
            # 不但可以訪問成員屬性
            print('我叫{}'.format(self.name))
            # 還可以調用成員方法
            self.run()
            
    fei = Person()
    fei.name = '路人甲'
    fei.run()
    fei.introduce()
    
    long = Person()
    long.name = '路人乙'
    long.introduce() 
    
    • 說明:
      1.類中的每個成員方法都有一個self參數,調用的時候不需要傳遞該參數
      2.該參數的名字可以不是self,只不過通常我們都使用這個
      3.self表示當前對象,對調用該方法self就代表誰,哪個對象調用就表示哪個對象
      4.通過self可以訪問成員屬性,也可以調用成員方法
  • __str__方法
    class Person:
    # 使用print方法打印對象,默認打印 類名 + 地址
    # 若想打印特定內容,重寫該方法即可,要求返回一個字符串
    def str(self):
    return ‘我叫{},今年{}’.format(self.name, self.age)

    james = Person()
    james.name = '路人丙'
    james.age = 33
    print(james)    
    
  • 構造方法:創建對象後,初始化屬性時,系統會自動調用該方法
    class Cat:
    def str(self):
    return ‘name:{},age:{},color:{}’.format(self.name, self.age, self.color)

        # 構造方法:創建對象後,初始化系統就會自動調用該方法
        def __init__(self, name, age, color):
            print('__init__')
            self.name = name
            self.age = age
            self.color = color
            
    # 這種形式比較繁瑣
    # tom = Cat()
    # tom.name = 'Tom'
    # tom.age = 3
    # tom.color = '藍色'
    
    # 這種比較簡潔
    tom = Cat('Tom', 3, '藍色')
    print(tom) 
    
  • 析構方法:當對象釋放時系統會自動調用,通常用於釋放資源
    class Pig:
    # 析構方法:當對象釋放時,系統會自動調用
    # 若手動使用del刪除,則會立即調用該方法
    # 該方法一般做資源釋放處理:數據庫連接斷開,文件關閉
    def del(self):
    print(‘大師兄,我不行了’)

    bajie = Pig()
    del bajie
    print('八戒,一路走好!')        
    
  • 示例:小明手裏有兩張牌,左右♥K,右手♠A,小明交換兩手的牌後,手裏分別是什麼?

    • 思路:

      • 先找到對象:左手、右手、♥K、♠A、小明
      • 根據對象抽象出對應的類:人、手、牌
      • 根據需要寫出相應的邏輯,很可能反過來完善類的設計
      • 按照題目要求創建相關對象,調用相關方法,實現相關功能
    • 代碼:

      對象:小明、左手、右手、♥K、♠A

      類:人、手、牌

      設計相應的類

      撲克牌

      class Poker:
      def init(self, color, number):
      self.color = color
      self.number = number

        def __str__(self):
        	return '{}{}'.format(self.color, self.number) 
      

      創建兩張牌

      p1 = Poker(‘♥’, ‘K’)
      p2 = Poker(‘♠’, ‘A’)

      手的類

      class Hand:
      def init(self, poker):
      self.poker = poker

        def hold_poker(self, poker):
            self.poker = poker
      

      創建左右兩隻手

      left_hand = Hand(p1)
      right_hand = Hand(p2)

      人的類

      class Person:
      def init(self, name, left_hand, right_hand):
      self.name = name
      self.left_hand = left_hand
      self.right_hand = right_hand

      # 展示手裏的牌
      def show(self):
      	print('{}張開手'.format(self.name), end=' ')
            print('左手:{}'.format(self.left_hand.poker), end=',')
            print('右手:{}'.format(self.right_hand.poker))
      
      # 交換兩手的牌
        def swap(self):
            self.left_hand.poker, self.right_hand.poker = self.right_hand.poker, self.left_hand.poker
            print('{}交換兩手的牌'.format(self.name))   
      

      創建小明對象

      xiaoming = Person(‘小明’, left_hand, right_hand)

      展示手裏的牌

      xiaoming.show()

      交換兩手的牌

      xiaoming.swap()

      #再次展示
      xiaoming.show()

常用內置函數

  • 內置函數:在類的內部,特定時機自動觸發的函數。

  • 示例:setattr、getattr、delattr
    class Person:
    def init(self, name):
    self.name = name

          def __str__(self):
              return '姓名:{}'.format(self.name)
    
          def __del__(self):
              print('對象即將銷燬')
              
          # 當獲取不存在的屬性時,會自動觸發該方法
          def __getattr__(self, item):
              if item == 'age':
                  return 18
              else:
                  return '你猜'
    
          # 當設置不存在的屬性時,會自動觸發該方法
          def __setattr__(self, key, value):
              print(key, value)
              self.__dict__[key] = value
    
          # 銷燬對象成員屬性時,會自動觸發該方法
          def __delattr__(self, item):
              print(item, '即將銷燬')
            
    xiaoming = Person('小明')
    xiaoming.age = 20
    print(xiaoming.age)
    # 存放對象的所有屬性
    # print(xiaoming.__dict__)
    # print(xiaoming)
    del xiaoming.age         
    
  • 將對象當做字典操作,特定時機會自動觸發的方法
    class Person:
    # 將對象當做字典操作,設置鍵值對時會觸發該方法
    def setitem(self, key, value):
    # print(key, value)
    self.dict[key] = value

        # 將對象當做字典操作,根據鍵獲取值時會觸發該方法
        def __getitem__(self, item):
            # print(item)
            return self.__dict__.get(item)
    
        # 將對象當做字典操作,刪除指定的鍵值對時自動觸發
        def __delitem__(self, key):
            del self.__dict__[key]
            
    xiaoming = Person()
    
    xiaoming['name'] = '小明'
    print(xiaoming.dict)
    
    print(xiaoming['name'])
    
    del xiaoming['name']         
    
  • 將對象當做函數調用時,會自動觸發下面方法
    class Person:
    # 將對象當做函數調用時,會自動觸發該方法
    def call(self, *args, **kwargs):
    # print(‘call’)
    return sum(args)

    xiaoming = Person()
    
    # 這樣操作,需要提供call方法
    ret = xiaoming(1, 2, 3, name='小明')
    print(ret)   
    
  • 函數判斷
    class A:
    def call(self, *args, **kwargs):
    pass

    def test():
        pass
    
    a = A()
    
    # 判斷是否可調用
    print(callable(test))
    print(callable(a))
    
    # 判斷是否擁有'__call__'屬性
    print(hasattr(test, '__call__'))
    print(hasattr(a, '__call__'))
    
    # 判斷是否是函數
    from inspect import isfunction
    print(isfunction(test))
    print(isfunction(a))
    

面向對象三大特點

  • 封裝:既可對數據結構進行封裝,又可對處理數據的方法進行封裝
  • 繼承:強調的父子類的關係
  • 多態:不同對象調用相同的方法,會有不同的響應

類的繼承

  • 相關概念

    • 繼承:父類的屬性和方法,子類直接擁有,稱爲繼承
    • 派生:子類在父類的基礎上衍生出新的特徵(屬性和行爲)
    • 總結:其實他們是一回事,只是描述問題的側重點不同(繼承強調相同點,派生強調不同點)
  • 繼承語法
    # class Animal(object):
    # 當沒有指定父類時,默認繼承object
    class Animal:
    def init(self, name):
    self.name = name

        def eat(self):
            print('小動物喜歡一天到晚吃個不停')
    
    # 繼承自Animal
    class Dog(Animal):
        pass
    
    d = Dog('旺財')
    # 可以擁有父類的方法
    d.eat()
    # 也可以擁有父類的屬性
    print(d.name)
    
  • 派生示例
    class Animal:
    def run(self):
    print(‘小動物喜歡成天跑個不停’)

    class Cat(Animal):
        def eat(self):
            print('貓喜歡吃老鼠')
    
    tom = Cat()
    
    tom.run()
    # 多出來的行爲
    tom.eat()
    
    # 多出來的屬性
    tom.color = '藍色'
    print(tom.color)
    
  • 重寫方法

    • 若父類的方法完全不合適,可以進行覆蓋重寫

    • 若父類的方法不夠完善,可以添枝加葉進行完善

    • 示例:
      class Animal:
      def eat(self):
      print(‘小動物一天到晚的出個不停’)

        def run(self):
            print('小動物一天到晚的四處連跑')
      

      class Cat(Animal):
      # 父類的方法完全不合適,覆蓋重寫
      def run(self):
      print(‘俺走的時貓步’)

        # 父類的方法部分合適,需要添加內容進行完善
        def eat(self):
            # 保留父類的內容,不建議使用此方式
            # Animal.eat(self)
            # super(Cat, self).eat()
            # 類名及self可以不傳
            super().eat()
            print('不過俺喜歡吃魚')
      

      jiafei = Cat()
      jiafei.run()
      jiafei.eat()

  • 多繼承:一個子類可以擁有多個父類
    class A:
    def eat(self):
    print(‘eat func in class A’)

    class B:
        def eat(self):
            print('eat func in class B')
    
    class C(A, B):
        def eat(self):
            # 這種方案是默認的繼承順序進行選擇的父類方法
            # super().eat()
            # 人爲指定調用某個父類的方法
            B.eat(self)
    
    c = C()
    c.eat()
    

訪問權限

  • 權限

    • 公有的:類中的普通的屬性和方法,默認都是公有的;可以在類內、類外、子類中使用
    • 私有的:定義時在前面添加兩個’_’,就變成了私有的;只能在類內使用,不能在類外及子類中使用
  • 示例:
    class Person:
    def init(self, name):
    self.name = name
    self.__age = 20

        def eat(self):
            print('民以食爲天')
    
        def __test(self):
            print('__test')
    xiaoming = Person('小明')
    print(xiaoming.name)
    xiaoming.eat()
    #不能在類外使用
    #print(xiaoming.__age)
    xiaoming._Person__test()
    print(xiaoming.dict)
    #儘管可以這樣訪問私有屬性,但是強烈建議不要這樣使用
    #print(xiaoming._Person__age)
    class Man(Person):
     def introduce(self):
          # 不能在子類中使用
          # print(self.__age)
          print('我叫{}'.format(self.name))
          self.eat()
    m = Man('亮亮')
    m.introduce()
    

類屬性

  • 說明:定義類時,寫在方法外的屬性,通常會寫在類的開頭,這樣的屬性稱爲類屬性

  • 示例:
    class Person:
    # 類屬性,通過類名訪問,屬於整個類,而不是某個對象
    # nation = ‘中國’

        # 限制可以使用的屬性,提高訪問的效率
        # 也可以提高訪問速度,減少內存使用
        __slots__ = ('name', 'age', 'nation')
    
        def __init__(self, name):
            self.name = name
            self.nation = 'china'
    p1 = Person('小明')
    p2 = Person('小紅')
    print(p1.name, p2.name)
    print(Person.nation)
    #p1.nation = 'china'
    print(p1.nation)
    print(p2.nation)
    #print(Person.nation)
    p1.age = 20
    #p1.height = 180
    
    #特殊的類屬性
    #表示類名的字符串
    
      print(Person.name)
    
    #表示父類構成的元組
    
      print(Person.bases)
    
    #存儲類的相關信息
    
      print(Person.dict)
    
    #限制可以使用的屬性
    
      print(Person.slots)
    

類方法

  • 說明:

    • 定義時使用classmethod裝飾器裝飾的方法
    • 使用時通過類名調用
  • 作用:

    • 可以創建對象或者簡潔的創建對象
    • 對外提供簡單易用的接口
  • 示例1:創建對象

    class Person:
        def eat(self):
            print('我喜歡吃麻辣燙,不要麻椒和辣椒')
    
        @classmethod
        def test(cls):
            print(cls)
            print('類方法')
    
        # 創建對象,或者簡潔的創建對象
        @classmethod
        def create(cls):
            p = cls()
            p.age = 1
            return p
    
    p1 = Person()
    p1.eat()
    
    # 通過類名調用
    Person.test()
    # 創建或簡潔的創建對象
    p2 = Person.create()
    print(type(p2))
    
  • 示例2:提供接口
    class Number:
    def init(self, num1, num2):
    self.num1 = num1
    self.num2 = num2

        def add(self):
            return self.num1 + self.num2
    
        def sub(self):
            return self.num1 - self.num2
    
        def mul(self):
            return self.num1 * self.num2
    
        def div(self):
            if self.num2 == 0:
                return None
            return self.num1 / self.num2
    
        # 對外提供簡單易用的接口
        @classmethod
        def pingfanghe(cls, num1, num2):
            n1 = cls(num1, num1)
            n12 = n1.mul()
    
            n2 = cls(num2, num2)
            n22 = n2.mul()
    
            n3 = cls(n12, n22)
            return n3.add()
    he = Number.pingfanghe(3, 4)
    print(he)
    

靜態方法

  • 說明:

    • 使用staticmethod裝飾器裝飾的方法(方法沒有cls參數)
    • 通過類名進行調用
  • 示例:
    class Person:
    @staticmethod
    def test():
    print(‘static method test’)

        # 創建對象
        @staticmethod
        def create():
            p = Person()
            return p
    #Person.test()
    #p = Person.create()
    #print(p)
    

    、 class Animal:
    def run(self):
    pass
    class Dog(Animal):
    def run(self):
    print(‘狗通常走S型’)
    class Cat(Animal):
    def run(self):
    print(‘貓平時走貓步,偶爾突然加速’)
    def test(obj):
    obj.run()
    d = Dog()
    c = Cat()
    test(d)
    test©

屬性函數

  • 說明:將成員方法當做屬性一樣進行訪問

  • 作用:保護特定屬性,或者對特定屬性進行處理

  • 示例:

    class User:
        def __init__(self, username, password):
            self.username = username
            self.__password = password
    
        # 該方法可以像成員屬性一樣訪問
        @property
        def password(self):
            print('有人想查看密碼')
            return '想偷看密碼,沒門'
            # return self.__password
    
        # 在設置密碼時,會自動調用
        @password.setter
        def password(self, password):
            print('@password.setter', password)
            self.__password = '加密' + password + '加密'
    
    
    u = User('xiaoming', '111111')
    # print(u.password())
    print(u.password)
    
    # 設置密碼,會自動調用setter方法
    u.password = 'abcde'
    

面向對象及異常處理

內置函數

  • 總結:initdelstr、attr系列、item系列、call

  • str__與__repr

    • 使用print/str方法時會自動觸發__str__方法,當__str__不存在,嘗試__repr__
    • 使用repr方法時會自動觸發__repr__方法
    • repr方法通常用於返回對象的字符串表示形式
    • 這兩個方法都只能返回字符串
    • eval方法可以將一個字符串當做有效的代碼執行
  • 算術運算符重載

    • 示例:
      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__')
            return Number(self.num + other)
      

      n = Number(100)
      ret = n + 200
      ret = 200 + n
      print(ret)
      n += 200 # n = n + 200
      print(n)

    • 自己測試
      加法:addraddiadd
      減法:subrsubisub
      乘法:mulrmulimul
      除法:truedivrtruedivitruediv
      求餘:__mod、rmodimod

  • 關係運算符重載
    >: gt
    =: ge
    <: lt
    <=: le
    ==: eq
    !=: ne

  • 示例
    class Number:
    def init(self, num):
    self.num = num

          def __gt__(self, other):
              print('__gt__')
              return self.num > 200
    
          def __lt__(self, other):
              print('__lt__')
              return self.num < other
    
          def __eq__(self, other):
              print('__eq__')
              return self.num == other
    
          # 當沒有此方法時,使用!=也會觸發__eq__方法
          def __ne__(self, other):
              print('__ne__')
              return self.num != other
        
    n = Number(100)
    
    # print(n > 200)
    # print(200 > n)
    # print(200 == n)
    print(200 != n)     
    

深淺拷貝

  • 引用計數

    • python中的所有變量都是對象,對象的管理採用的時引用計數的方式
    • 當多一個變量指向對象計數值加1,當少一個變指向對象計數值減1,減到0是,釋放對象(del)
  • 函數傳參

    • 對於不可變的變量來說,函數中不可能改傳遞過來的變量
    • 對於可變的容器對象及自定義對象,作爲函數參數傳遞時,傳遞的是引用,可以修改該對象
  • 深淺拷貝
    class Person:
    def del(self):
    print(‘對象釋放’)

    p1 = Person()
    p2 = p1
    
    print(id(p1))
    print(id(p2))
    
    del p1
    del p2
    print('OVER')
    
    def test(m):
    	# m += 1
    	m[0] = 300
    
    # n = 100
    n = [100, 200]
    
    test(n)
    print(n)
    
    import copy
    
    lt = [1, 2, [3, 4]]
    
    # 淺拷貝,只拷貝對象本身,不拷貝對象中的元素
    # lt2 = lt.copy()
    # 淺拷貝
    lt2 = copy.copy(lt)
    
    # 深拷貝:不但拷貝對象本身,還拷貝對象中的元素
    lt2 = copy.deepcopy(lt)
    lt[0] = 100
    lt2 = 300
    
    print(id(lt))
    print(id(lt2))
    print(lt)
    print(lt2)
    

數據持久化(pickle)

  • 說明:數據持久化存儲方案,普通文件、序列化、數據庫

  • 示例:
    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)
    # 轉換爲bytes類型
    
    # s = pickle.dumps(xiaoming)
    # print(s)
    
    # 從字節流中提取對象
    # xm = pickle.loads(s)
    
    # print(xm)
    # 保存到文件中
    # fp = open('data.txt', 'wb')
    
    # pickle.dump(xiaoming, fp)
    # 從文件中獲取對象
    
    fp = open('data.txt', 'rb')
    xm = pickle.load(fp)
    print(xm)
    

異常處理

  • 相關概念

    • 錯誤:程序運行之前的語法問題,如:關鍵字、縮進、括號不成對等
    • 異常:在程序運行過程中出現的問題,如:未定義變量、除數爲0、屬性不存在等
  • 異常處理

    • 說明:異常處理可以理解爲特殊的流程控制語句,可以提高代碼的健壯性。
  • 異常語法:
    try:
    print(‘正常代碼’)
    # print(a)
    3/0
    except Exception as e:
    # Exception 是所有異常的基類,此處可以捕獲所有的異常
    print(‘出現異常’)
    print(e)

      print('其他內容')
    
  • 多個異常
    # 分類捕獲異常
    ‘’’
    try:
    # print(a)
    # 3/0
    d = {}
    print(d[‘name’])
    except NameError as e:
    print(‘NameError:’, e)
    except ZeroDivisionError as e:
    print(‘ZeroDivisionError:’, e)
    except Exception as e:
    print(‘OtherError:’, e)
    ‘’’

    try:
        # print(a)
        # 3/0
        fp = open('123.txt')
    except (NameError, ZeroDivisionError) as e:
        # 將某些異常進行統一處理,寫在一個元組中即可
        print(e)
    except:
        print('其他異常')
    
  • 完整結構(else-finally)
    try:
    print(‘正常代碼’)
    print(a)
    except:
    # 出現異常時執行
    print(‘出現異常’)
    else:
    # 正常結束(沒有異常)時會執行
    print(‘正常結束’)
    finally:
    # 無論有無異常,都會執行
    print(‘最後執行’)
    else:正常結束時執行else中的代碼
    finally:無論有無異常,最後都執行

  • 拋出異常:raise
    try:
    print(‘正常代碼’)
    # 根據業務邏輯的需要,手動拋出異常
    raise Exception(‘手動拋出的異常’)
    except Exception as e:
    print(‘異常:’, e)

    print('OVER')
    
  • 異常嵌套(try-except結構中再次使用try-except結構)
    print(‘我要去上班,什麼事也阻止不了我上班的腳步’)
    try:
    print(‘我準備騎電動車’)
    raise Exception(‘昨天晚上不知道哪個缺德的傢伙把我充電器拔了’)
    print(‘騎車提前到達公司’)
    except Exception as e:
    print(e)
    try:
    print(‘我準備做公交車’)
    raise Exception(‘等了20分鐘一直沒有公交車,果斷放棄’)
    print(‘坐公交車準時到達公司’)
    except Exception as e:
    print(e)
    print(‘我準備打車’)
    print(‘打車還是快,一會就到達公司’)

    print('熱情滿滿的開始一天的工作')
    
  • 自定義異常類(需要繼承自官方的異常基類Exception)
    # 自定義異常類
    class MyException(Exception):
    def init(self, msg):
    self.msg = msg

        def __str__(self):
            return self.msg
    
        # 特定異常標準處理方案
        def deal(self):
            print('處理特定的自定義異常')
            
    try:
        print('正常執行')
      	# 手動拋出自定義異常
      	raise MyException('出現了自定義異常')
    except MyException as e:
        print(e)
      	# 調用方法,處理異常
      	e.deal()
    
  • 特殊場景

    • 當我們進行文件操作時,無論過程中是否有異常,最終我們一定得進行關閉操作
    • 使用with語句,可以保證文件的關閉,無論中間過程是否出現異常

      fp = open(‘test.txt’, ‘r’)

      # 中間無論有無異常,最後一定得關閉文件
      # fp.close()
      
      with open('test.txt', 'r') as fp:
          content = fp.read(5)
          print(content)
          # 此處不要考慮文件的關閉問題,也不用是否有異常
      
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章