python 中面向對象的概念
原文
域和作用空間
本地域,函數域(nonlocal)和 全局域(global)
def scope_test(): def do_local(): spam = "local spam" def do_nonlocal(): nonlocal spam spam = "nonlocal spam" def do_global(): global spam spam = "global spam" spam = "test spam" do_local() print("After local assignment:", spam) do_nonlocal() print("After nonlocal assignment:", spam) do_global() print("After global assignment:", spam) scope_test() print("In global scope:", spam)
輸出的結果是
After local assignment: test spam After nonlocal assignment: nonlocal spam After global assignment: nonlocal spam In global scope: global spam
* 簡要解釋一下:
本地域作用於當前子函數範圍,函數域作用於整個函數範圍,全局域作用於函數以及函數外部。優先級是本地域>函數域>全局域。
類的基本概念
最簡單的類的定義形式看起來像這樣:你可以將一個類定義放置於 if
語句的分支中, 或一個函數中.
class ClassName: <statement-1> . . . <statement-N>
類的屬性和類的初始化方法
比如:
class MyClass: """A simple example class""" i = 12345 def f(self): return ‘hello world‘
可以給 MyClass.i
賦值以改變其數值. __doc__
也是一個合法的屬性,返回屬於這個類的 docstring : "A simple example class"
.
實例化的操作 (“調用” 一個類對象) 創建了空的對象. 在創建實例時, 很多類可能都需要有特定的初始狀態. 所以一個類可以定義一個特殊的方法, 稱為 __init__()
>>> class Complex: ... def __init__(self, realpart, imagpart): ... self.r = realpart ... self.i = imagpart ... >>> x = Complex(3.0, -4.5) >>> x.r, x.i (3.0, -4.5)
實例對象
可以對實例對象做什麽? 唯一能理解的操作就是屬性引用. 有兩種合法的屬性, 數據屬性和方法.(在 Python 中, 方法的概念並不是類實例所特有: 其他對象類型也可以有方法. 例如, 列表對象有 append, insert, remove, sort, 及等等的方法. 但是, 在下面的討論中, 我們指的就是類實例對象的方法, 除非特別指出.)(對象不等於類)
方法對象
調用方法對象
x.f()
在多數情況下, 調用一個方法 (有個 n 個參數), 和調用相應的函數 (也有那 n 個參數, 但是再額外加入一個使用該方法的對象), 是等價的.
當一個實例屬性被引用時, 但是不是數據屬性, 那麽它的類將被搜索. 如果該名字代表一個合法的類屬性並且是一個函數對象, 一個方法對象就會被創建, 通過包裝 (指向) 實例對象, 而函數對象仍然只是在抽象的對象中: 這就是方法對象. 當方法對象用一個參數列表調用, 新的參數列表會從實例對象中重新構建, 然後函數對象則調用新的參數列表.
註意:
數據屬性覆寫了同名的方法屬性; 為了避免這個偶然的名字沖突, 在大型的程序中這會導致很難尋找的 bug, 使用某些命名約定是非常明智的, 這樣可以最小的避免沖突. 可能的約定包括大寫方法名稱, 在數據類型前增加特殊的前綴 (或者就是一個下劃線), 或對於方法使用動詞, 而數據成員則使用名詞.
繼承
派生類的定義:
class DerivedClassName(BaseClassName): <statement-1> . . . <statement-N>
BaseClassName
的定義對於派生類而言必須是可見的. 在基類的地方, 任意的表達式都是允許的. 這就會非常有用, 比如基類定義在另一個模塊:
class DerivedClassName(modname.BaseClassName):
Python 有兩個內置函數用於繼承:
- 使用
isinstance()
檢查實例的類型:isinstance(obj, int)
只有在obj.__class__
是int
或其派生類時才為True
. - 使用
issubclass()
用於檢查類的繼承關系:issubclass(bool, int)
會返回True
, 因為bool
是int
的派生類. 但是,issubclass(float, int)
會是False
因為float
並不是int
的派生類.
多重繼承
Python 支持多重繼承.
class DerivedClassName(Base1, Base2, Base3): <statement-1> . . . <statement-N>
在繼承體系中, 同樣的類只會被搜尋一次. 如果一個屬性在 DerivedClassName
中沒有被找到, 它就會搜尋 Base1, 然後 (遞歸地) 搜尋 Base1
的基類, 然後如果還是沒有找到, 那麽就會搜索 Base2
, 等等.
私有變量
在 Python 之中, 並不存在那種無法訪問的 “私有” 變量. 但是, 在多數的 Python 代碼中有個約定: 以一個下劃線帶頭的名字 (如 _spam
) 應該作為非公共的 API (不管是函數, 方法或者數據成員). 這應該作為具體的實現, 而且變化它也無須提醒.
有這樣的一種機制稱為 name mangling. 任何如 __spam
形式的標識符, (在開頭至少有兩個下劃線) 將被替換為 _classname__spam
, 此處的 classname
就是當前的類. 這樣的處理無須關註標識符的句法上的位置, 盡管它是在一個類的定義中.
數據類型
綁定一些命名的數據. 一個空的類定義就將很好:
class Employee: pass john = Employee() # Create an empty employee record # Fill the fields of the record john.name = ‘John Doe‘ john.dept = ‘computer lab‘ john.salary = 1000
一段 Python 代碼中如果希望一個抽象的數據類型, 那麽可以通過傳遞一個類給那個方法, 就好像有了那個數據類型一樣.
python 中面向對象的概念