Python從設計之初就已經是一門物件導向的語言,正因為如此,在Python中創建一個類別和物件是很容易的。本章節我們將詳細介紹Python的物件導向程式設計。
如果你以前沒有接觸過物件導向的程式語言,那你可能需要先了解一些物件導向語言的一些基本特徵,在頭腦裡頭形成一個基本的物件導向的概念,這樣有助於你更容易的學習Python的物件導向程式設計。
接下來我們先來簡單的了解下面向對象的一些基本特徵。
物件導向技術簡介
類別(Class): 用來描述具有相同的屬性和方法的物件的集合。它定義了該集合中每個物件所共有的屬性和方法。物件是類別的實例。
類別變數:類別變數在整個實例化的物件中是公用的。類別變數定義在類別中且在函數體之外。類別變數通常不作為實例變數使用。
資料成員:類別變數或實例變數用於處理類別及其實例物件的相關的資料。
方法重載:如果從父類別繼承的方法不能滿足子類別的需求,可以對其進行改寫,這個過程叫方法的覆寫(override),也稱為方法的重載。
實例變數:定義在方法中的變量,只作用於目前實例的類別。
繼承:即 一個衍生類別(derived class)繼承基底類別(base class)的欄位和方法。繼承也允許把一個衍生類別的物件當作一個基底類別物件。例如,有這樣一個設計:一個Dog類型的物件派生自Animal類,這是 模擬"是一個(is-a)"關係(例圖,Dog是一個Animal)。
實例化:建立一個類別的實例,類別的具體物件。
方法:類別中定義的函數。
物件:透過類別定義的資料結構實例。物件包括兩個資料成員(類別變數和實例變數)和方法。
建立類別
使用class語句來建立一個新類別,class之後為類別的名稱並以冒號結尾,如下實例:
class ClassName:
類串 class_suite #類體 類的幫助資訊可以透過ClassName.__doc__檢視。 class_suite 由類別成員,方法,資料屬性組成。 實例以下是一個簡單的Python類別實例: class Employee: 'Common base class for Count. def __init__(self, name, salary ): self.name = name self.salary = salary= def displayCount(self):
print "Total Employee %d" % Employee.empCount
def displayEmployee(self):
print "Name : ", self.name, ", Salary: ", self.salary的所有實例之間共用。你可以在內部類別或外部類別使用Employee.empCount存取。
第一種方法__init__()方法是一種特殊的方法,被稱為類別的建構函式或初始化方法,當建立了這個類別的實例時就會呼叫該方法
建立實例物件
要建立一個類別的實例,你可以使用類別的名稱,並透過__init__方法接受參數。
"This would create first object of Employee class"
emp1 = Employee("Zara", 2000)
"Thir. Employee("Manni", 5000)
存取屬性
您可以使用點(.)來存取物件的屬性。使用以下類別的名稱來存取類別變數:
emp1.displayEmployee()
emp2.displayEmployee()
print "Total Employee%d"
完整實例:#!/usr/bin/python class Employee: def __init__(self, name, salary):
self.name = name self.salary = salary displayCount(self):
print "Total Employee %d" % Employee.empCount
def dis中舉行", self.salary
"This would 。 playEmployee()
emp2.displayEmployee()
print "Total Employee %d" % Employee.empCount
: 執行上述ary: 2000Name : Manni ,Salary: 5000Total Employee 2 你可以加入,刪除,修改類別的屬性,如下圖
emp
你可以加入,刪除,修改類別的屬性,
emp1.age = 8 # 修改'age' 屬性
del emp1.age # 刪除'age' 屬性
att
att
你也可以使用以下函數的方式來存取屬性。 , default]) : 存取物件的屬性。 hasattr(obj,name) : 檢查是否存在一個屬性。 setattr(obj,name,value) : 設定一個屬性。如果屬性不存在,會建立一個新屬性。 delattr(obj, name) : 刪除屬性。 hasattr(emp1, 'age') # 如果存在 'age' 屬性回傳 True。 getattr(emp1, 'age') # 傳回'age' 屬性的值setattr(emp1, 'age', 8) # 新增屬性'刪除屬性'age' Python內建類別屬性__dict__ : 類別的屬性(包含一個字典,由類別的資料屬性所組成)__doc 類__module__: 類別定義所在的模組(類別的全名是'__main__.className',如果類別位於一個導入模組mymod中,那麼className.__module__ 等於mymod)
__bases__ : 類別的所有父類別構成元素(包含了以個由所有父類別組成的元組)
Python內建類別屬性呼叫實例如下:
#!/usr/bin/python
. employees' empCount = 0 def __init__(self, name, .salary = salary Employee.empCount += 1 def displayCount( 。 ", Salary: ", self.salary
print "Employee.__doc__:", Employee.__doc__print "Employee.__name__:", Employee.__name__print "Employee.__module__:", Employloyee.__Hconloyee. __bases__print "Employee.__dict__:", Employee.__dict__ 執行上述程式碼輸出sEmployee.__name__: Employee Employee.__module__: __main__Employee.__bases__: ()Employee.__dict__: {'__module__': '__main____','displayCount' p. 2,
'displayEmployee':
__
'__init__':4function python物件銷毀(垃圾回收)同Java語言一樣,Python使用了引用計數這項簡單技術來追蹤記憶體中的物件。 在Python內部記錄所有使用中的物件各有多少引用。 一個內部追蹤變量,稱為一個引用計數器。當物件被建立時, 就建立了一個引用計數, 當這個物件不再需要時, 也就是說, 這個物件的參考計數變成0 時, 它被垃圾回收。但是回收不是"立即"的, 由解釋器在適當的時機,將垃圾物件佔用的記憶體空間回收。
a = 40 # 建立物件
b = a # 增加引用. 的計數
del a # 減少引用 的數量
b = 100 # 減少引用 的數
c[0] = -1
垃圾回收機制不僅針對引用計數為0的對象,同樣也可以處理循環引用的情況。循環引用指的是,兩個物件相互引用,但是沒有其他變數引用他們。這種情況下,僅使 用引用計數是不夠的。 Python 的垃圾收集器實際上是一個引用計數器和一個循環垃圾收集器。作為引用計數的補充, 垃圾收集器也會留心被分配的總量很大(及未通過引用計數銷毀的那些)的對象。 在這種情況下, 解釋器會暫停下來, 試圖清理所有未引用的循環。
實例
析構函數__del__ ,__del__在物件消逝的時候被調用,當物件不再被使用時,__del__方法運作:
#!/usr/bin/python
class Point:
def __init( self, x=0, y=0):
self.x def __del__(self):
class_name = self.__class__ .__name__
print class_name, "destroyed"
pt1 = Point()
pt2 =ptpt111115% id(pt2), id(pt3) # 印刷物件的id
del pt1
del pt2
del pt3
<p></p><p>以上實例運作結果如下:</p><p></p><pre class="brush:php;toolbar:false"><p>以上實例運作結果如下:</p><p></p><pre class="brush:php;toolbar:false"><p></p><p>以上實例運作結果如下:</p><p></p><pre class="brush:php;toolbar:false"><p>以上實例運作結果324</p><p></p>Point destroyed<p></p> <p> </p><p></p>注意:通常你需要在單獨的文件中定義一個類,<p></p>類的繼承<p></p>面向對象的編程帶來的主要好處之一是代碼的重用,實現這種重用的方法之一是通過繼承機制。繼承完全可以理解成類別之間的類型和子類型關係。 <p></p>需要注意的地方:繼承語法 class 衍生類別名(基底類別名稱)://... 基底類別名稱寫作括號裡,基本類別是在類別定義的時候,在元組之中指明的。 <p></p>在python中繼承中的一些特點:<p></p>1:在繼承中基類的構造(__init__()方法)不會被自動調用,它需要在其派生類的構造中親自專門調用。 <p></p>2:在呼叫基底類別的方法時,需要加上基底類別的類別名稱前綴,且需要帶上self參數變數。區別於在類別中呼叫普通函數時並不需要帶上self參數<p></p>3:Python總是先尋找對應類型的方法,如果它不能在衍生類別中找到對應的方法,它才開始到基底類別中逐個查找。 (先在本類別中找出呼叫的方法,找不到才去基底類別找)。 <p></p>如果在繼承元組中列了一個以上的類,那麼它就被稱作"多重繼承" 。 <p></p>語法:<p></p>衍生類別的聲明,與他們的父類別類似,繼承的基底類別清單跟在類別名稱之後,如下所示:<p></p><p></p><p></p>class SubClassName (ParentClass1[, ParentClass2, ... ]):<p></p> 'Optional class documentation string'<p></p> class_suite<p></p> <p></p><p></p>/ <p> </p><p>class Parent: # define parent class</p><p> parentAttr = 100</p><p> def __init__(self):</p><p> print "Calling parent constructor"</p> 'Calling parent method'<p></p> <p></p> def setAttr(self, attr):<p></p> Parent.parentAttr = attr<p></p> <p></p> def getAttr(self):<p></p> print <p>class Child(Parent): # define child class</p><p> def __init__(self):</p><p> print </p> print 'Calling child method'<p></p> <p></p>c = Child() # 實例化子類別<p></p>c.childMethod() # 將子類別呼叫的方法<p> # 再次呼叫父類別的方法</p> <p>c.getAttr() Sharp </p><p>Calling parent method</p><p>Parent attribute : 200 </p><p> </p><p></p><p>你可以繼承多個類別</p><p></p><p></p><p>class A: # define your calss B</p><p>... ..</p><p> </p><p>class C(A, B): # subclass of A and B</p><p>.....</p><p> </p><p></p><p></p> <p></p><p></p>你可以使用is <p></p>issubclass() - 布林函數判斷一個類別是另一個類別的子類別或子孫類,語法:issubclass(sub,sup)<p></p>isinstance(obj, Class) 布林函數如果obj是Class類別的實例物件或是一個Class子類別的實例物件則回傳true。 <p></p>重載方法<p></p>如果你的父類方法的功能不能滿足你的需求,你可以在子類重載你父類的方法:<p></p>實例:<p></p><p></p><p></p>實例:<p></p><p></p><p> /python</p><p> </p><p>class Parent: # 定義父類別</p><p> def myMethod(self): </p>class Child(Parent): # 定義子類別<p></p> def myMethod(self) :<p></p> print 'Calling child method'<p></p> <p></p>c = Child() 呼叫重載方法<p></p> <p></p><p></p>執行上述程式碼輸出結果如下:<p> </p><p></p><p></p>Calling child method<p></p> <p></p><p></p>基礎重載方法<p></p>下表列出了一些通用的功能,你可以在自己的類重寫:簡單的呼叫<p></p><p></p>1 __init__ ( self [,args...] )<p>建構子</p>簡單的呼叫方法: obj = className(args) <p></p>2 析 del__簡單的呼叫方法: dell obj <p></p>3 __repr__( self )<p>轉化為解釋器讀取的形式</p>簡單的呼叫方法: repr(obj) 人閱讀的形式<p>簡單的呼叫方法: str(obj) </p><p>5 __cmp__ ( self, x )</p>物件比較<p>簡單的呼叫方法: cmp(obj, x) 運算子重載運算實例如下:</p><p></p><p></p><p>#!/usr/bin/python</p><p> </p><p>class Vector:</p><p> </p><p> self.b = b </p><p> </p><p> def __str__(self):<br><br> return 'Vector (%d, __(self,other):</p><p> return Vector( self.a + other.a, self.b + other.b)<br><br> </p><p>v1 = Vector(2,10)<br><br>v2 = Vector(5,-2) </p><p> <br>以上程式碼執行結果如下圖:<br></p><p><br><br></p>Vector(7,8)<p></p> <p></p><p></p>隱藏資料<p> </p><p></p><p>隱藏資料</p><p>在把類別變數名稱或成員函數前面加兩個底線即可實現資料隱藏的功能,這樣,對於類別的實例來說,其變數名稱和成員函數是不能使用的,對於其類別的繼承類別來說,也是隱藏的,這樣,其繼承類別可以定義其一模一樣的變數名或成員函數名,而不會造成命名衝突。 例:</p><p></p><p></p><p>#!/usr/bin/python</p><p> </p><p>class JustCounter:</p><p> __secretCount = 0</p> .__secretCount += 1<p></p> print self.__secretCount<p></p> <p></p>counter = JustCounter()<p></p>counter.count()<p></p>counter.count()<p></p>print counter.__secretCount<p></p> <p></p><p> </p><p>2</p> <p>Traceback (most recent call last):</p><p> File "test.py", line 12, in <module></module></p><p> print counter.__secsCount </p><p> </p><p></p><p>Python不允許實例化的類別存取隱藏數據,但你可以使用object._className__attrName存取屬性,將如下程式碼替換以上程式碼的最後一行程式碼:</p><p></p><p></p><p>............. ..........</p><p>print counter._JustCounter__secretCount</p><p> </p><p></p><p>執行上述程式碼,執行結果如下:</p><p></p><p>1</p>