我們好幾次提到了“對象(object)”這個詞,但一直沒有真正定義它。編程環境中的對象很象現實世界中的對象。實際的對象有一定的形狀、大小、重量和其它特徵。實際的對象還能夠對其環境進行響應、與其它對象交互或執行任務。計算機中的對象試圖模擬我們身邊現實世界中的對象,包括象文檔、日程表和業務過程這樣的抽象對象。
類似於實際的對象,幾個計算機對象可能共享共同的特徵,同時保持它們自己相對較小的變異特徵。想一想您在書店中看到的書籍。書籍的每個物理副本都可能有污跡、幾張破損的書頁或唯一的標識號。儘管每本書都是唯一的對象,但都擁有相同標題的每本書都只是原始模板的實例,並保留了原始模板的大多數特徵。
對於面向對象的類和類實例也是如此。例如,可以看到每個 Python 字符串都被賦予了一些屬性,dir()
函數揭示了這些屬性。在前一個示例中,我們定義了自己的
Person
類,它擔任創建個別 Person 實例的模板,每個實例都有自己的 name 和 age 值,同時共享自我介紹的能力。這就是面向對象。
於是在計算機術語中,對象是擁有標識和值的事物,屬於特定類型、具有特定特徵和以特定方式執行操作。並且,對象從一個或多個父類繼承了它們的許多屬性。除了關鍵字和特殊符號(象運算符,如
+
、-
、*
、**
、/
、%
、<
、>
等)外,Python 中的所有東西都是對象。Python 具有一組豐富的對象類型:字符串、整數、浮點、列表、元組、字典、函數、類、類實例、模塊、文件等。
當您有一個任意的對象(也許是一個作爲參數傳遞給函數的對象)時,可能希望知道一些關於該對象的情況。在本節中,我們將向您展示如何讓 Python 對象回答如下問題:
- 對象的名稱是什麼?
- 這是哪種類型的對象?
- 對象知道些什麼?
- 對象能做些什麼?
- 對象的父對象是誰?
並非所有對象都有名稱,但那些有名稱的對象都將名稱存儲在其 __name__
屬性中。注:名稱是從對象而不是引用該對象的變量中派生的。下面這個示例着重說明了這種區別:
清單 27. 名稱中有什麼?
$ python Python 2.2.2 (#1, Oct 28 2002, 17:22:19) [GCC 3.2 (Mandrake Linux 9.0 3.2-1mdk)] on linux2 Type "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 模塊中是很常見的:
清單 28. 用於執行或導入的測試
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
模塊中定義的類型相比較:
清單 29. 我是您的類型嗎?
>>> 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()
函數給任何給定對象返回唯一的標識符:
清單 30. 目的地……
>>> print id.__doc__ id(object) -> integer Return the identity of an object. This is guaranteed to be unique among simultaneously 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 False 0 >>> blist is clist # Ditto 1 >>> 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()
函數來完成,如本例所示:
清單 31. 具有一個屬性;獲得一個屬性
>>> print hasattr.__doc__ hasattr(object, name) -> Boolean Return 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]) -> value Get 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't exist; without it, an exception is raised in that case. >>> hasattr(id, '__doc__') 1 >>> print getattr(id, '__doc__') id(object) -> integer Return the identity of an object. This is guaranteed to be unique among simultaneously existing objects. (Hint: it's the object's memory address.) |
可以調用表示潛在行爲(函數和方法)的對象。可以用 callable()
函數測試對象的可調用性:
清單 32. 您能爲我做些事情嗎?
>>> print callable.__doc__ callable(object) -> Boolean Return 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()
函數測試對象,以確定它是否是某個特定類型或定製類的實例:
清單 33. 您是那些實例中的一個嗎?
>>> print isinstance.__doc__ isinstance(object, class-or-type-or-tuple) -> Boolean Return 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 for isinstance(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()
函數使我們可以查看一個類是不是繼承了另一個類:
清單 34. 您是我母親嗎?
>>> print issubclass.__doc__ issubclass(C, B) -> Boolean Return 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 >>> |
讓我們將上一節中討論的幾種檢查技術結合起來。爲了做到這一點,要定義自己的函數 — interrogate()
,它打印有關傳遞給它的任何對象的各種信息。以下是代碼,後面是其用法的幾個示例:
清單 35. 誰也沒料到它
>>> def interrogate(item): ... """Print useful information about item.""" ... if hasattr(item, '__name__'): ... print "NAME: ", item.__name__ ... if hasattr(item, '__class__'): ... print "CLASS: ", item.__class__.__name__ ... print "ID: ", id(item) ... print "TYPE: ", type(item) ... print "VALUE: ", repr(item) ... print "CALLABLE:", ... if callable(item): ... print "Yes" ... else: ... print "No" ... if hasattr(item, '__doc__'): ... doc = getattr(item, '__doc__') ... doc = doc.strip() # Remove leading/trailing whitespace. ... firstline = doc.split('\n')[0] ... print "DOC: ", firstline ... >>> interrogate('a string') # String object CLASS: str ID: 141462040 TYPE: <type 'str'> VALUE: 'a string' CALLABLE: No DOC: str(object) -> string >>> interrogate(42) # Integer object CLASS: int ID: 135447416 TYPE: <type 'int'> VALUE: 42 CALLABLE: No DOC: int(x[, base]) -> integer >>> interrogate(interrogate) # User-defined function object NAME: interrogate CLASS: function ID: 141444892 TYPE: <type 'function'> VALUE: <function interrogate at 0x86e471c> CALLABLE: Yes DOC: Print useful information about item. |
正如您在最後一個示例中所看到的,interrogate()
函數甚至可以應用於它本身。您沒有再比它更具“自省性”的工具了。
原文地址:http://www.ibm.com/developerworks/cn/linux/l-pyint/index2.html