編程環境中的對象很象現實世界中的對象。實際的對象有一定的形狀、大小、重量和其它特徵。實際的對象還能夠對其環境進行響應、與其它對象互動或執行任務。電腦中的對象試圖類比我們身邊現實世界中的對象,包括象文檔、議程表和業務過程這樣的抽象對象。
類似於實際的對象,幾個電腦對象可能共用共同的特徵,同時保持它們自己相對較小的變異特徵。想一想您在書店中看到的書籍。書籍的每個物理副本都可能有汙跡、幾張破損的書頁或唯一的標識號。儘管每本書都是唯一的對象,但都擁有相同標題的每本書都只是原始模板的執行個體,並保留了原始模板的大多數特徵。
對於物件導向的類和類執行個體也是如此。例如,可以看到每個 Python 字串都被賦予了一些屬性, dir()
函數揭示了這些屬性。在前一個樣本中,我們定義了自己的 Person
類,它擔任建立個別 Person 執行個體的模板,每個執行個體都有自己的 name 和 age 值,同時共用自我介紹的能力。這就是物件導向。
於是在電腦術語中,對象是擁有標識和值的事物,屬於特定類型、具有特定特徵和以特定方式執行操作。並且,對象從一個或多個父類繼承了它們的許多屬性。除了關鍵字和特殊符號(象運算子,如 +
、 -
、 *
、 **
、 /
、 %
、 <
、 >
等)外,Python 中的所有東西都是對象。Python 具有一組豐富的物件類型:字串、整數、浮點、列表、元組、字典、函數、類、類執行個體、模組、檔案等。
當您有一個任意的對象(也許是一個作為參數傳遞給函數的對象)時,可能希望知道一些關於該對象的情況。在本節中,我們將向您展示如何讓 Python 對象回答如下問題:
- 對象的名稱是什嗎?
- 這是哪種類型的對象?
- 對象知道些什嗎?
- 對象能做些什嗎?
- 對象的父物件是誰?
名稱
並非所有對象都有名稱,但那些有名稱的對象都將名稱儲存在其 __name__
屬性中。註:名稱是從對象而不是引用該對象的變數中派生的。下面這個樣本著重說明了這種區別:
清單 1. 名稱中有什嗎?
$ pythonPython 2.2.2 (#1, Oct 28 2002, 17:22:19)[GCC 3.2 (Mandrake Linux 9.0 3.2-1mdk)] on linux2Type "help", "copyright", "credits" or "license" for more information.>>> dir() # The dir() function['__builtins__', '__doc__', '__name__']>>> directory = dir # Create a new variable>>> directory() # Works just like the original object['__builtins__', '__doc__', '__name__', 'directory']>>> dir.__name__ # What's your name?'dir'>>> directory.__name__ # My name is the same'dir'>>> __name__ # And now for something completely different'__main__'
模組擁有名稱,Python 解譯器本身被認為是頂級模組或主模組。當以互動的方式運行 Python 時,局部 __name__
變數被賦予值 '__main__'
。同樣地,當從命令列執行 Python 模組,而不是將其匯入另一個模組時,其 __name__
屬性被賦予值 '__main__'
,而不是該模組的實際名稱。這樣,模組可以查看其自身的 __name__
值來自行確定它們自己正被如何使用,是作為另一個程式的支援,還是作為從命令列執行的主應用程式。因此,下面這條慣用的語句在 Python 模組中是很常見的:
清單 2. 用於執行或匯入的測試
if __name__ == '__main__': # Do something appropriate here, like calling a # main() function defined elsewhere in this module. main()else: # Do nothing. This module has been imported by another # module that wants to make use of the functions, # classes and other useful bits it has defined.
類型
type()
函數有助於我們確定對象是字串還是整數,或是其它類型的對象。它通過傳回型別對象來做到這一點,可以將這個類型對象與 types
模組中定義的類型相比較:
清單 3. 我是您的類型嗎?
>>> import types>>> print types.__doc__Define names for all type symbols known in the standard interpreter.Types that are part of optional modules (e.g. array) are not listed.>>> dir(types)['BufferType', 'BuiltinFunctionType', 'BuiltinMethodType', 'ClassType','CodeType', 'ComplexType', 'DictProxyType', 'DictType', 'DictionaryType','EllipsisType', 'FileType', 'FloatType', 'FrameType', 'FunctionType','GeneratorType', 'InstanceType', 'IntType', 'LambdaType', 'ListType','LongType', 'MethodType', 'ModuleType', 'NoneType', 'ObjectType', 'SliceType','StringType', 'StringTypes', 'TracebackType', 'TupleType', 'TypeType','UnboundMethodType', 'UnicodeType', 'XRangeType', '__builtins__', '__doc__','__file__', '__name__']>>> s = 'a sample string'>>> type(s)<type 'str'>>>> if type(s) is types.StringType: print "s is a string"...s is a string>>> type(42)<type 'int'>>>> type([])<type 'list'>>>> type({})<type 'dict'>>>> type(dir)<type 'builtin_function_or_method'>
標識
先前我們說過,每個對象都有標識、類型和值。值得注意的是,可能有多個變數引用同一對象,同樣地,變數可以引用看起來相似(有相同的類型和值),但擁有截然不同標識的多個對象。當更改對象時(如將某一項添加到列表),這種關於對象標識的概念尤其重要,如在下面的樣本中, blist
和 clist
變數引用同一個列表對象。正如您在樣本中所見, id()
函數給任何給定對象返回唯一的標識符:
清單 4. 目的地……
>>> print id.__doc__id(object) -> integerReturn the identity of an object. This is guaranteed to be unique amongsimultaneously existing objects. (Hint: it's the object's memory address.)>>> alist = [1, 2, 3]>>> blist = [1, 2, 3]>>> clist = blist>>> clist[1, 2, 3]>>> blist[1, 2, 3]>>> alist[1, 2, 3]>>> id(alist)145381412>>> id(blist)140406428>>> id(clist)140406428>>> alist is blist # Returns 1 if True, 0 if False0>>> blist is clist # Ditto1>>> clist.append(4) # Add an item to the end of the list>>> clist[1, 2, 3, 4]>>> blist # Same, because they both point to the same object[1, 2, 3, 4]>>> alist # This one only looked the same initially[1, 2, 3]
屬性
我們已經看到對象擁有屬性,並且 dir()
函數會返回這些屬性的列表。但是,有時我們只想測試一個或多個屬性是否存在。如果對象具有我們正在考慮的屬性,那麼通常希望只檢索該屬性。這個任務可以由 hasattr()
和 getattr()
函數來完成,如本例所示:
清單 5. 具有一個屬性;獲得一個屬性
>>> print hasattr.__doc__hasattr(object, name) -> BooleanReturn whether the object has an attribute with the given name.(This is done by calling getattr(object, name) and catching exceptions.)>>> print getattr.__doc__getattr(object, name[, default]) -> valueGet a named attribute from an object; getattr(x, 'y') is equivalent to x.y.When a default argument is given, it is returned when the attribute doesn'texist; without it, an exception is raised in that case.>>> hasattr(id, '__doc__')1>>> print getattr(id, '__doc__')id(object) -> integerReturn the identity of an object. This is guaranteed to be unique amongsimultaneously existing objects. (Hint: it's the object's memory address.)
可調用
可以調用表示潛在行為(函數和方法)的對象。可以用 callable()
函數測試對象的可調用性:
清單 6. 您能為我做些事情嗎?
>>> print callable.__doc__callable(object) -> BooleanReturn whether the object is callable (i.e., some kind of function).Note that classes are callable, as are instances with a __call__() method.>>> callable('a string')0>>> callable(dir)1
執行個體
在 type()
函數提供對象的類型時,還可以使用 isinstance()
函數測試對象,以確定它是否是某個特定類型或定製類的執行個體:
清單 7. 您是那些執行個體中的一個嗎?
>>> print isinstance.__doc__isinstance(object, class-or-type-or-tuple) -> BooleanReturn whether an object is an instance of a class or of a subclass thereof.With a type as second argument, return whether that is the object's type.The form using a tuple, isinstance(x, (A, B, ...)), is a shortcut forisinstance(x, A) or isinstance(x, B) or ... (etc.).>>> isinstance(42, str)0>>> isinstance('a string', int)0>>> isinstance(42, int)1>>> isinstance('a string', str)1
子類
我們先前提到過,定製類的執行個體從該類繼承了屬性。在類這一層級,可以根據一個類來定義另一個類,同樣地,這個新類會按照層次化的方式繼承屬性。Python 甚至支援多重繼承,多重繼承意味著可以用多個父類來定義一個類,這個新類繼承了多個父類。 issubclass()
函數使我們可以查看一個類是不是繼承了另一個類:
清單 8. 您是我母親嗎?
>>> print issubclass.__doc__issubclass(C, B) -> BooleanReturn whether class C is a subclass (i.e., a derived class) of class B.>>> class SuperHero(Person): # SuperHero inherits from Person...... def intro(self): # but with a new SuperHero intro... """Return an introduction."""... return "Hello, I'm SuperHero %s and I'm %s." % (self.name, self.age)...>>> issubclass(SuperHero, Person)1>>> issubclass(Person, SuperHero)0>>>