Python 高級之 ------面向對象

Python從設計之初就已經是一門面向對象的語言,正因爲如此,在Python中創建一個類和對象是很容易的。

主要是以下的知識點

1. 創建類

用 class 語句來創建一個新類,class 之後爲類的名稱並以冒號結尾

    class ClassName:
       '類的幫助信息'   #類文檔字符串
       class_suite  #類體

* 類的幫助信息可以通過ClassName.doc查看。
* class_suite 由類成員,方法,數據屬性組成。
* 類的方法與普通的函數只有一個特別的區別——它們必須有一個額外的第一個參數名稱, 按照慣例它的名稱是 self。
* self代表類的實例(對象),代表當前對象的地址而非類 self 代表類的實例,self 在定義類的方法時是必須有的,雖然在調用時不必傳入相應的參數
* self.class 則指向類。self 不是 python 關鍵字,我們把他換成 xxx任意的 也是可以的。
* 類繼承 繼承語法 class 派生類名(基類名)://… 基類名寫在括號裏,基本類是在類定義的時候,在元組之中指明的。
* 在繼承中基類的構造(init()方法)不會被自動調用,它需要在其派生類的構造中親自專門調用。
* 在調用基類的方法時,需要加上基類的類名前綴,且需要帶上self參數變量。區別在於類中調用普通函數時並不需要帶上self參數
* Python總是首先查找對應類型的方法,如果它不能在派生類中找到對應的方法,它纔開始到基類中逐個查找。(先在本類中查找調用的方法,找不到纔去基類中找)
* 如果在繼承元組中列了一個以上的類,那麼它就被稱作”多重繼承” 。
* issubclass() - 布爾函數判斷一個類是另一個類的子類或者子孫類,語法:issubclass(sub,sup)
* isinstance(obj, Class) 布爾函數如果obj是Class類的實例對象或者是一個Class子類的實例對象則返回true。
語法:
* 方法重寫 同java
* 方法重載 函數中的參數個數 重載 運算符重載 (在類的對象中 重載對應的方法
這裏寫圖片描述

2. 創建類的實例 (對象)

  • 在 Python 中並沒有new這個關鍵字,類的實例化類似函數調用方式。以下使用類的名稱 Employee 來實例化,並通過 init 方法接受參數

        "創建 Employee 類的第一個對象"
        emp1 = Employee("Zara", 2000)
        "創建 Employee 類的第二個對象"
        emp2 = Employee("Manni", 5000)
    
  • 類裏面的方法 用戶自己寫的全是公有的非靜態的只能用類的對象來訪問 直接 對象.方法即可

    • 公有靜態方法 由於所有方法都包含self 所以公用靜態方法 必須傳入你new的對象 所以可以用對象.方法來代替 所以這個方法雖然是靜態的其實 是面向某個實例的 emp1 = Employee(“Manni”, 5000) Employee.displayEmployee(emp1) emp1.displayEmployee() 後面的兩句是等效的
    • 私有方法 兩個下劃線開頭,聲明該方法爲私有方法,不能在類地外部調用。在類的內部調用 self.__private_methods
  • 類裏面的變量

    • 公有的非靜態成員變量 一般都是在init()方法中定義的。slef.aa=1 類的成員變量必須賦值 不像其他語言有默認缺省值
    • 私有的非靜態成員變量 兩個下劃線開頭,聲明該屬性爲私有,不能在類的外部被使用或直接訪問。使用的時候同上self.__private_attrs。
    • 公有的靜態成員變量 在類中直接命名 的值將在這個類的所有實例之間共享。

      public void aa() == def aa(slef)
      private void bb() == def __bb(slef)
      public static int cc == cc=0
      public int dd == __int__()方法裏面的 slef.dd=0
      private int ee == __ee=0
      
  • 受保護類型的是以_單下劃線開頭的 同私有變量 保護類型的就是隻在自己類中和子類中可以用
  • 你可以添加,刪除,修改類的屬性,即便類已經定義好了。直接對象.成員變量 儘量不要這樣去做 這樣很難去擴展了。

        emp1.age = 7  # 添加一個 'age' 屬性
        emp1.age = 8  # 修改 'age' 屬性
        del emp1.age  # 刪除 'age' 屬性
    
  • 也可以使用以下函數的方式來訪問屬性:

        hasattr(emp1, 'age')    # 如果存在 'age' 屬性返回 True。
        getattr(emp1, 'age')    # 返回 'age' 屬性的值
        setattr(emp1, 'age', 8) # 添加屬性 'age' 值爲 8
        delattr(emp1, 'age')    # 刪除屬性 'age'
    
  • Python內置類屬性(靜態成員方法)
    • dict : 類的屬性(包含一個字典,由類的數據屬性組成)
    • doc :類的文檔字符串
    • name: 類名
    • module: 類定義所在的模塊(類的全名是’main.className’,如果類位於一個導入模塊mymod中,className.module 等於 mymod)
    • bases : 類的所有父類構成元素(包含了一個由所有父類組成的元組)
    • *

3. python對象實例銷燬(垃圾回收機制)

  • Python 使用了引用計數這一簡單技術來跟蹤和回收垃圾。在 Python 內部記錄着所有使用中的對象各有多少引用。
  • 在引用計數的基礎上,還可以通過“標記-清除”(mark and sweep)解決容器對象可能產生的循環引用的問題。
  • 通過“分代回收”(generation collection)以空間換取時間來進一步提高垃圾回收的效率。
  • 當對象被創建時, 就創建了一個引用計數, 當這個對象不再需要時, 也就是說, 這個對象的引用計數變爲0 時, 它被垃圾回收。但是回收不是”立即”的, 由解釋器在適當的時機,將垃圾對象佔用的內存空間回收。

3.1 引用計數

  1. 在Python中,大多數對象的生命週期都是通過對象的引用計數來管理的。
  2. 原理:當一個對象的引用被創建或者複製時,對象的引用計數加1;當一個對象的引用被銷燬時,對象的引用計數減1;當對象的引用計數減少爲0時,就意味着對象已經沒有被任何人使用了,可以將其所佔用的內存釋放了。
  3. 雖然引用計數必須在每次分配和釋放內存的時候加入管理引用計數的動作,然而與其他主流的垃圾收集技術相比,引用計數有一個最大的有點,即“實時性”,任何內存,一旦沒有指向它的引用,就會立即被回收。而其他的垃圾收集計數必須在某種特殊條件下(比如內存分配失敗)才能進行無效內存的回收。
  4. 引用計數機制執行效率問題:引用計數機制所帶來的維護引用計數的額外操作與Python運行中所進行的內存分配和釋放,引用賦值的次數是成正比的。而這點相比其他主流的垃圾回收機制,比如“標記-清除”,“停止-複製”,是一個弱點,因爲這些技術所帶來的額外操作基本上只是與待回收的內存數量有關。
  5. 如果說執行效率還僅僅是引用計數機制的一個軟肋的話,那麼很不幸,引用計數機制還存在着一個致命的弱點,正是由於這個弱點,使得俠義的垃圾收集從來沒有將引用計數包含在內,能引發出這個致命的弱點就是循環引用(也稱交叉引用)。循環引用可以使一組對象的引用計數不爲0,然而這些對象實際上並沒有被任何外部對象所引用,它們之間只是相互引用。這意味着不會再有人使用這組對象,應該回收這組對象所佔用的內存空間,然後由於相互引用的存在,每一個對象的引用計數都不爲0,因此這些對象所佔用的內存永遠不會被釋放。

3.2 標記-清除

  1. “標記-清除”是爲了解決循環引用的問題。可以包含其他對象引用的容器對象(比如:list,set,dict,class,instance)都可能產生循環引用。
  2. 原理:“標記-清除”採用了更好的做法,我們並不改動真實的引用計數,而是將集合中對象的引用計數複製一份副本,改動該對象引用的副本。對於副本做任何的改動,都不會影響到對象生命週期的維護。
  3. 這個計數副本的唯一作用是尋找root object集合(該集合中的對象是不能被回收的)。當成功尋找到root object集合之後,首先將現在的內存鏈表一分爲二,一條鏈表中維護root object集合,成爲root鏈表,而另外一條鏈表中維護剩下的對象,成爲unreachable鏈表。之所以要剖成兩個鏈表,是基於這樣的一種考慮:現在的unreachable可能存在被root鏈表中的對象,直接或間接引用的對象,這些對象是不能被回收的,一旦在標記的過程中,發現這樣的對象,就將其從unreachable鏈表中移到root鏈表中;當完成標記後,unreachable鏈表中剩下的所有對象就是名副其實的垃圾對象了,接下來的垃圾回收只需限制在unreachable鏈表中即可。

3.3 分代回收

  1. 背景:分代的垃圾收集技術是在上個世紀80年代初發展起來的一種垃圾收集機制,一系列的研究表明:無論使用何種語言開發,無論開發的是何種類型,何種規模的程序,都存在這樣一點相同之處。即:一定比例的內存塊的生存週期都比較短,通常是幾百萬條機器指令的時間,而剩下的內存塊,起生存週期比較長,甚至會從程序開始一直持續到程序結束。
  2. 從前面“標記-清除”這樣的垃圾收集機制來看,這種垃圾收集機制所帶來的額外操作實際上與系統中總的內存塊的數量是相關的,當需要回收的內存塊越多時,垃圾檢測帶來的額外操作就越多,而垃圾回收帶來的額外操作就越少;反之,當需回收的內存塊越少時,垃圾檢測就將比垃圾回收帶來更少的額外操作。爲了提高垃圾收集的效率,採用“空間換時間的策略”。
  3. 原理:將系統中的所有內存塊根據其存活時間劃分爲不同的集合,每一個集合就成爲一個“代”,垃圾收集的頻率隨着“代”的存活時間的增大而減小。也就是說,活得越長的對象,就越不可能是垃圾,就應該減少對它的垃圾收集頻率。那麼如何來衡量這個存活時間:通常是利用幾次垃圾收集動作來衡量,如果一個對象經過的垃圾收集次數越多,可以得出:該對象存活時間就越長。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章