Chapter 5:對象和面向對象
兩種 import
方法
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
類能十分出色地模仿字典。在 Python 2.2 和其後的版本中,你可以直 接從UserDict
内建資料類型繼承。這樣之前的代碼可以改寫成如下代碼。且無需導入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__
語句,即使用該語句時,python自動調用instance["key"]
方法,下同instace.__getitem__("key")
-
:模拟__setitem__
instance["key"] = value
-
: 傳回對象的機器友好的字元串表示__repr__
-
: 傳回對象的人類友好的字元串表示,兩者的差別詳見此處。__str__
-
: 模拟__cmp__
cmp(instance1, instance2)
-
: 模拟__len__
len(instance)
-
模拟__delitem__
del instance[key]
- 更多專用類方法詳見官方文檔。
類屬性
在 Java 中,靜态變量 (在 Python 中叫類屬性) 和執行個體變量 (在 Python 中叫數 據屬性) 兩者都是緊跟在類定義之後定義的 (一個有關鍵字,一個沒有)。 在 Python 中,隻有類屬性可以定義在這裡,資料屬性定義在
static
方法中
__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'