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'