Python 從出現以來一直是一種面向對象的語言。因此,創建和使用類和對象非常容易。本章幫助您成為使用 Python 面向對象編程支持的專家。
如果您以前沒有任何面向對象 (OO) 編程的經驗,您可能需要查閱有關它的入門課程或至少某種教程,以便掌握基本概念。
但是,這里是面向對象編程 (OOP) 的小介紹,可讓您快速入門 -
OOP 術語概述
類- 對象的用戶定義原型,定義了一組表征類的任何對象的屬性。屬性是通過點符號訪問的數據成員(類變量和實例變量)和方法。
類變量- 由類的所有實例共享的變量。類變量在類內定義,但在類的任何方法之外。類變量不像實例變量那樣頻繁使用。
數據成員- 保存與類及其對象關聯的數據的類變量或實例變量。
函數重載- 將多個行為分配給特定函數。執行的操作因所涉及的對象或參數的類型而異。
Instance variable - 在方法內部定義的變量,僅屬于類的當前實例。
繼承- 將類的特征轉移到從它派生的其他類。
Instance - 某個類的單個對象。例如,屬于類 Circle 的對象 obj 是類 Circle 的一個實例。
實例化- 創建一個類的實例。
Method - 在類定義中定義的一種特殊函數。
Object - 由其類定義的數據結構的唯一實例。一個對象包括數據成員(類變量和實例變量)和方法。
運算符重載- 將多個函數分配給特定運算符。
創建類
class語句創建一個新的類定義。類的名稱緊跟關鍵字class后跟冒號,如下所示 -
class ClassName:
'Optional class documentation string'
class_suite
該類有一個文檔字符串,可以通過ClassName.__doc__訪問。
class_suite由定義類成員、數據屬性和函數的所有組件語句組成。
例子
以下是一個簡單的 Python 類的示例 -
class Employee:
'Common base class for all employees'
empCount = 0
def __init__(self, name, salary):
self.name = name
self.salary = salary
Employee.empCount += 1
def displayCount(self):
print "Total Employee %d" % Employee.empCount
def displayEmployee(self):
print "Name : ", self.name, ", Salary: ", self.salary
變量empCount是一個類變量,其值在此類的所有實例之間共享。這可以作為Employee.empCount從類內部或類外部訪問。
第一個方法__init__()是一種特殊的方法,稱為類構造函數或初始化方法,Python 在創建此類的新實例時會調用該方法。
您可以像普通函數一樣聲明其他類方法,但每個方法的第一個參數是self除外。Python 為您將self參數添加到列表中;調用方法時不需要包含它。
創建實例對象
要創建類的實例,您可以使用類名調用該類并傳入其__init__方法接受的任何參數。
"This would create first object of Employee class"
emp1 = Employee("Zara", 2000)
"This would create second object of Employee class"
emp2 = Employee("Manni", 5000)
訪問屬性
您可以使用帶有對象的點運算符訪問對象的屬性。類變量將使用類名訪問,如下所示 -
emp1.displayEmployee()
emp2.displayEmployee()
print "Total Employee %d" % Employee.empCount
現在,將所有概念放在一起 -
現場演示
#!/usr/bin/python
class Employee:
'Common base class for all employees'
empCount = 0
def __init__(self, name, salary):
self.name = name
self.salary = salary
Employee.empCount += 1
def displayCount(self):
print "Total Employee %d" % Employee.empCount
def displayEmployee(self):
print "Name : ", self.name, ", Salary: ", self.salary
"This would create first object of Employee class"
emp1 = Employee("Zara", 2000)
"This would create second object of Employee class"
emp2 = Employee("Manni", 5000)
emp1.displayEmployee()
emp2.displayEmployee()
print "Total Employee %d" % Employee.empCount
執行上述代碼時,會產生以下結果 -
Name : Zara ,Salary: 2000
Name : Manni ,Salary: 5000
Total Employee 2
您可以隨時添加、刪除或修改類和對象的屬性 -
emp1.age = 7 # Add an 'age' attribute.
emp1.age = 8 # Modify 'age' attribute.
del emp1.age # Delete 'age' attribute.
您可以使用以下函數,而不是使用普通語句來訪問屬性 -
getattr(obj, name[, default]) - 訪問對象的屬性。
hasattr(obj,name) -檢查屬性是否存在。
setattr (obj,name,value) - 設置屬性。如果屬性不存在,那么它將被創建。
delattr (obj, name) - 刪除一個屬性。
hasattr(emp1, 'age') # Returns true if 'age' attribute exists
getattr(emp1, 'age') # Returns value of 'age' attribute
setattr(emp1, 'age', 8) # Set attribute 'age' at 8
delattr(empl, 'age') # Delete attribute 'age'
內置類屬性
每個 Python 類都遵循內置屬性,并且可以像任何其他屬性一樣使用點運算符訪問它們 -
__dict__ - 包含類名稱空間的字典。
__doc__ - 類文檔字符串或無,如果未定義。
__name__ - 類名。
__module__ - 定義類的模塊名稱。此屬性在交互模式下為“__main__”。
__bases__ - 包含基類的可能為空的元組,按照它們在基類列表中出現的順序排列。
對于上面的類,讓我們嘗試訪問所有這些屬性 -
現場演示
#!/usr/bin/python
class Employee:
'Common base class for all employees'
empCount = 0
def __init__(self, name, salary):
self.name = name
self.salary = salary
Employee.empCount += 1
def displayCount(self):
print "Total Employee %d" % Employee.empCount
def displayEmployee(self):
print "Name : ", self.name, ", Salary: ", self.salary
print "Employee.__doc__:", Employee.__doc__
print "Employee.__name__:", Employee.__name__
print "Employee.__module__:", Employee.__module__
print "Employee.__bases__:", Employee.__bases__
print "Employee.__dict__:", Employee.__dict__
執行上述代碼時,會產生以下結果 -
Employee.__doc__: Common base class for all employees
Employee.__name__: Employee
Employee.__module__: __main__
Employee.__bases__: ()
Employee.__dict__: {'__module__': '__main__', 'displayCount':
<function displayCount at 0xb7c84994>, 'empCount': 2,
'displayEmployee': <function displayEmployee at 0xb7c8441c>,
'__doc__': 'Common base class for all employees',
'__init__': <function __init__ at 0xb7c846bc>}
銷毀對象(垃圾收集)
Python 會自動刪除不需要的對象(內置類型或類實例)以釋放內存空間。Python 定期回收不再使用的內存塊的過程稱為垃圾收集。
Python 的垃圾收集器在程序執行期間運行,并在對象的引用計數達到零時觸發。對象的引用計數隨著指向它的別名數量的變化而變化。
對象的引用計數在被分配新名稱或放置在容器(列表、元組或字典)中時會增加。使用del刪除對象、重新分配其引用或超出范圍時,對象的引用計數會減少。當一個對象的引用計數達到零時,Python 會自動收集它。
a = 40 # Create object <40>
b = a # Increase ref. count of <40>
c = [b] # Increase ref. count of <40>
del a # Decrease ref. count of <40>
b = 100 # Decrease ref. count of <40>
c[0] = -1 # Decrease ref. count of <40>
當垃圾收集器銷毀孤立實例并回收其空間時,您通常不會注意到。但是一個類可以實現特殊方法__del__(),稱為析構函數,當實例即將被銷毀時調用該方法。此方法可用于清理實例使用的任何非內存資源。
例子
這個 __del__() 析構函數打印即將被銷毀的實例的類名 -
現場演示
#!/usr/bin/python
class Point:
def __init__( self, x=0, y=0):
self.x = x
self.y = y
def __del__(self):
class_name = self.__class__.__name__
print class_name, "destroyed"
pt1 = Point()
pt2 = pt1
pt3 = pt1
print id(pt1), id(pt2), id(pt3) # prints the ids of the obejcts
del pt1
del pt2
del pt3
執行上述代碼時,會產生以下結果 -
3083401324 3083401324 3083401324
Point destroyed
注意- 理想情況下,您應該在單獨的文件中定義您的類,然后您應該使用import語句將它們導入您的主程序文件中。
類繼承
您可以通過在新類名后面的括號中列出父類,從預先存在的類派生類來創建一個類,而不是從頭開始。
子類繼承其父類的屬性,您可以像在子類中定義這些屬性一樣使用這些屬性。子類也可以覆蓋父類的數據成員和方法。
句法
派生類的聲明很像它們的父類;但是,在類名之后給出了要繼承的基類列表 -
class SubClassName (ParentClass1[, ParentClass2, ...]):
'Optional class documentation string'
class_suite
例子
現場演示
#!/usr/bin/python
class Parent: # define parent class
parentAttr = 100
def __init__(self):
print "Calling parent constructor"
def parentMethod(self):
print 'Calling parent method'
def setAttr(self, attr):
Parent.parentAttr = attr
def getAttr(self):
print "Parent attribute :", Parent.parentAttr
class Child(Parent): # define child class
def __init__(self):
print "Calling child constructor"
def childMethod(self):
print 'Calling child method'
c = Child() # instance of child
c.childMethod() # child calls its method
c.parentMethod() # calls parent's method
c.setAttr(200) # again call parent's method
c.getAttr() # again call parent's method
執行上述代碼時,會產生以下結果 -
Calling child constructor
Calling child method
Calling parent method
Parent attribute : 200
類似地,您可以從多個父類中驅動一個類,如下所示 -
class A: # define your class A
.....
class B: # define your class B
.....
class C(A, B): # subclass of A and B
.....
您可以使用 issubclass() 或 isinstance() 函數來檢查兩個類和實例的關系。
如果給定的子類sub確實是超類sup的子類,則issubclass(sub, sup)布爾函數返回 true 。
isinstance(obj, Class)布爾函數如果obj是Class 的實例或者是 Class的子類的實例,則返回 true
覆蓋方法
您始終可以覆蓋您的父類方法。重寫父類方法的一個原因是您可能希望子類中有特殊或不同的功能。
例子
現場演示
#!/usr/bin/python
class Parent: # define parent class
def myMethod(self):
print 'Calling parent method'
class Child(Parent): # define child class
def myMethod(self):
print 'Calling child method'
c = Child() # instance of child
c.myMethod() # child calls overridden method
執行上述代碼時,會產生以下結果 -
Calling child method
基礎重載方法
下表列出了您可以在自己的類中覆蓋的一些通用功能 -
編號 方法、描述和樣品調用
1
__init__ ( self [,args...] )
構造函數(帶有任何可選參數)
示例調用:obj = className(args)
2
__del__(自我)
析構函數,刪除一個對象
示例調用:del obj
3
__repr__(自我)
可評估的字符串表示
示例調用:repr(obj)
4
__str__( 自我 )
可打印的字符串表示
示例調用:str(obj)
5
__cmp__ ( 自我, x )
對象比較
示例調用:cmp(obj, x)
重載運算符
假設您創建了一個 Vector 類來表示二維向量,當您使用加號運算符將它們相加時會發生什么?Python 很可能會對你大喊大叫。
但是,您可以在您的類中定義__add__方法來執行向量加法,然后加號運算符將按預期運行 -
例子
現場演示
#!/usr/bin/python
class Vector:
def __init__(self, a, b):
self.a = a
self.b = b
def __str__(self):
return 'Vector (%d, %d)' % (self.a, self.b)
def __add__(self,other):
return Vector(self.a + other.a, self.b + other.b)
v1 = Vector(2,10)
v2 = Vector(5,-2)
print v1 + v2
執行上述代碼時,會產生以下結果 -
Vector(7,8)
數據隱藏
對象的屬性在類定義之外可能可見,也可能不可見。您需要使用雙下劃線前綴命名屬性,然后這些屬性對于外人來說是不直接可見的。
例子
現場演示
#!/usr/bin/python
class JustCounter:
__secretCount = 0
def count(self):
self.__secretCount += 1
print self.__secretCount
counter = JustCounter()
counter.count()
counter.count()
print counter.__secretCount
執行上述代碼時,會產生以下結果 -
1
2
Traceback (most recent call last):
File "test.py", line 12, in <module>
print counter.__secretCount
AttributeError: JustCounter instance has no attribute '__secretCount'
Python 通過在內部更改名稱以包含類名來保護這些成員。您可以訪問諸如object._className__attrName 之類的屬性。如果您將最后一行替換如下,那么它對您有用 -
.........................
print counter._JustCounter__secretCount
執行上述代碼時,會產生以下結果 -
1
2
2