天天看點

《Dive into Python》讀書筆記之對象和面向對象

Chapter 5:對象和面向對象

兩種

import

方法

import random   # 使用時需要加上random字首
random.randint  # <bound method Random.randint of <random.Random object at 0x10101f620>>
randint         # name 'randint' is not defined
from random import randint  # 可以直接使用
randint         # <bound method Random.randint of <random.Random object at 0x10101f620>>
from random import *    # 導入所有方法
           

類的定義

from UserDict import UserDict
class FileInfo(UserDict):   # 建立FileInfo類并繼承UserDict類
    "store file metadata"   # 類的docstring
    def __init__(self, filename=None):  #【1】
        UserDict.__init__(self)         #【2】
        self["name"] = filename         #【3】
           

【1】:

__init__

類似構造函數,self為每一個類方法都需要指定的參數,調用時不需指定,會自動加上。

【2】:Python不會自動調用父類的構造函數,必須顯式調用父類合适的方法,包括

__init__

函數。

【3】:一般隻能用

self.name

方式來指定成員變量,但此處因為繼承了

UserDict

類,是以可以使用

self["name"]

方法來指派。參考stackoverflow上的一篇文章:http://stackoverflow.com/questions/4117060/confused-by-selfname-filename。

垃圾回收

當指派給執行個體的變量超出作用域時,python會自動釋放其空間。在下面的代碼中,每一次執行

leakmem

函數時,之前的f已經超出了作用域被銷毀,故執行過程中始終隻有一個執行個體,不會發生記憶體洩漏。

def leakmem(): 
    f = fileinfo.FileInfo('/music/_singles/kairo.mp3') 

for i in range(100):
    leakmem()
           

探索UserDict:一個封裝類

  • 可以在ipython中

    from UserDict import UserDict

    ,再用

    UserDict?

    檢視其内容和相關屬性。
  • 在 Python 2.2 之前的版本中,你不可以直接子類化字元串、清單以及字典之類的内建資料類型。作為補償,Python 提供封裝類來模拟内建資料類型的行 為,比如:

    UserString

    UserList

     和 

    UserDict

    。通過混合使用普通和特殊方法, 

    UserDict

     類能十分出色地模仿字典。在 Python 2.2 和其後的版本中,你可以直 接從 

    dict

     内建資料類型繼承。這樣之前的代碼可以改寫成如下代碼。且無需導入

    UserDict

    子產品和初始化子類。
  • 考慮兩個類,base 和 child,base 中的 方法 a 需要調用 self.b;而我們又在 child 中覆寫了方法 b。然後我們建立一個 child 的執行個體,ch。調用 ch.a,那麼此時的方法 a 調用的 b 函數将不是 base.b, 而是 child.b。
class FileInfo(dict): 
    "store file metadata"
    def __init__(self, filename=None):
        self["name"] = filename
           

專用類方法

  • __getitem__

    :使類可以模拟使用

    instance["key"]

    語句,即使用該語句時,python自動調用

    instace.__getitem__("key")

    方法,下同
  • __setitem__

    :模拟

    instance["key"] = value

  • __repr__

    : 傳回對象的機器友好的字元串表示
  • __str__

    : 傳回對象的人類友好的字元串表示,兩者的差別詳見此處。
  • __cmp__

    : 模拟

    cmp(instance1, instance2)

  • __len__

    : 模拟

    len(instance)

  • __delitem__

     模拟

    del instance[key]

  • 更多專用類方法詳見官方文檔。

類屬性

在 Java 中,靜态變量 (在 Python 中叫類屬性) 和執行個體變量 (在 Python 中叫數 據屬性) 兩者都是緊跟在類定義之後定義的 (一個有

static

關鍵字,一個沒有)。 在 Python 中,隻有類屬性可以定義在這裡,資料屬性定義在

__init__

方法中
class counter:
    count = 0   # 緊跟類名定義類屬性
    def __init__(self):
    self.__class__.count += 1   # 通過該方法修改類屬性 【1】

counter.count   # 0
c = counter()   
c.count         # 1
counter.count   # 1
d = counter()
d.count         # 2
c.count         # 2
counter.count   # 2
           

【1】:

__class__

是每個類執行個體的一個内置屬性 (也是每個類的)。它是一個類的引 用,而 self 是一個類 (在本例中,是 counter 類) 的執行個體。

私有函數

  • 如果一個 Python 函數,類方法,或屬性的名字以兩個下劃線開始 (但不是結束),它是私有的;其它所有的都是公有的。
  • 在 Python 中,所有的專用方法 (像 

    __setitem__

    ) 和内置屬性 (像 

    __doc__

    ) 遵守一 個标準的命名習慣:開始和結束都有兩個下劃線。命名自己的私有函數時要避免這種做法。
class Test:
    def _print(self):
        print "hello, world!"
    def __print(self):
        print "can you see me?"

t = Test()  
t._print()   # "hello, world!"
t.__print()  # AttributeError: Test instance has no attribute '__print'