自從存在以來,Python一直是面向?qū)ο蟮恼Z言。 因此,創(chuàng)建和使用類和對象是非常容易的。 本章將學(xué)習如何使用Python面向?qū)ο缶幊獭?/p>
如果您以前沒有面向?qū)ο?OO)編程的經(jīng)驗,可能需要查閱介紹面向?qū)ο?OO)編程課程或至少學(xué)習一些有關(guān)教程,以便掌握基本概念。
下面是面向?qū)ο缶幊?OOP)的一個小介紹,以幫助您快速入門學(xué)習 -
OOP術(shù)語概述
obj屬于Circle類,它是Circle類的實例。class語句創(chuàng)建一個新的類定義。 類的名稱緊跟在class關(guān)鍵字之后,在類的名稱之后緊跟冒號,如下 -
class ClassName:
'Optional class documentation string'
class_suite
ClassName.__doc__訪問。class_suite由定義類成員,數(shù)據(jù)屬性和函數(shù)的所有組件語句組成。示例
以下是一個簡單的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 __()是一種特殊的方法,當創(chuàng)建此類的新實例時,該方法稱為Python構(gòu)造函數(shù)或初始化方法。
聲明其他類方法,如正常函數(shù),但每個方法的第一個參數(shù)是self。 Python將self參數(shù)添加到列表中; 調(diào)用方法時不需要包含它。
要創(chuàng)建類的實例,可以使用類名調(diào)用該類,并傳遞其__init__方法接受的任何參數(shù)。
## This would create first object of Employee class
emp1 = Employee("Maxsu", 2000)
## This would create second object of Employee class
emp2 = Employee("Kobe", 5000)
可以使用帶有對象的點(.)運算符來訪問對象的屬性。 類變量將使用類名訪問如下 -
emp1.displayEmployee()
emp2.displayEmployee()
print ("Total Employee %d" % Employee.empCount)
現(xiàn)在把所有的概念放在一起 -
#!/usr/bin/python3
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("Maxsu", 2000)
#This would create second object of Employee class"
emp2 = Employee("Kobe", 5000)
emp1.displayEmployee()
emp2.displayEmployee()
print ("Total Employee %d" % Employee.empCount)
當執(zhí)行上述代碼時,會產(chǎn)生以下結(jié)果 -
Name : Maxsu ,Salary: 2000
Name : Kobe ,Salary: 5000
Total Employee 2
可以隨時添加,刪除或修改類和對象的屬性 -
emp1.salary = 7000 # Add an 'salary' attribute.
emp1.name = 'xyz' # Modify 'age' attribute.
del emp1.salary # Delete 'age' attribute.
如果不是使用普通語句訪問屬性,可以使用以下函數(shù) -
getattr(obj,name [,default]) - 訪問對象的屬性。hasattr(obj,name) - 檢查屬性是否存在。setattr(obj,name,value) - 設(shè)置一個屬性。如果屬性不存在,那么它將被創(chuàng)建。delattr(obj,name) - 刪除一個屬性。下面是一此使用示例 -
hasattr(emp1, 'salary') # Returns true if 'salary' attribute exists
getattr(emp1, 'salary') # Returns value of 'salary' attribute
setattr(emp1, 'salary', 7000) # Set attribute 'salary' at 7000
delattr(emp1, 'salary') # Delete attribute 'salary'
每個Python類保持以下內(nèi)置屬性,并且可以像任何其他屬性一樣使用點運算符訪問它們 -
__dict__ - 包含該類的命名空間的字典。__doc__ - 類文檔字符串或無,如果未定義。__name__ - 類名。__module__ - 定義類的模塊名稱。此屬性在交互模式下的值為“main”。__bases__ - 一個包含基類的空元組,按照它們在基類列表中出現(xiàn)的順序。對于上述類,嘗試訪問所有這些屬性 -
#!/usr/bin/python3
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)
emp1 = Employee("Maxsu", 2000)
emp2 = Employee("Bryant", 5000)
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__ )
當執(zhí)行上述代碼時,會產(chǎn)生以下結(jié)果 -
Employee.__doc__: Common base class for all employees
Employee.__name__: Employee
Employee.__module__: __main__
Employee.__bases__: (<class 'object'>,)
Employee.__dict__: {
'displayCount': <function Employee.displayCount at 0x0160D2B8>,
'__module__': '__main__', '__doc__': 'Common base class for all employees',
'empCount': 2, '__init__':
<function Employee.__init__ at 0x0124F810>, 'displayEmployee':
<function Employee.displayEmployee at 0x0160D300>,
'__weakref__':
<attribute '__weakref__' of 'Employee' objects>, '__dict__':
<attribute '__dict__' of 'Employee' objects>
}
Python自動刪除不需要的對象(內(nèi)置類型或類實例)以釋放內(nèi)存空間。 Python定期回收不再使用的內(nèi)存塊的過程稱為垃圾收集。
Python的垃圾收集器在程序執(zhí)行期間運行,當對象的引用計數(shù)達到零時觸發(fā)。 對象的引用計數(shù)隨著指向它的別名數(shù)量而變化。
當對象的引用計數(shù)被分配一個新名稱或放置在容器(列表,元組或字典)中時,它的引用計數(shù)會增加。 當用del刪除對象的引用計數(shù)時,引用計數(shù)減少,其引用被重新分配,或者其引用超出范圍。 當對象的引用計數(shù)達到零時,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>
通常情況下,垃圾回收器會銷毀孤立的實例并回收其空間。 但是,類可以實現(xiàn)調(diào)用析構(gòu)函數(shù)的特殊方法__del__(),該方法在實例即將被銷毀時被調(diào)用。 此方法可能用于清理實例使用的任何非內(nèi)存資源。
示例
這個__del__()析構(gòu)函數(shù)打印要被銷毀的實例的類名 -
#!/usr/bin/python3
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
當執(zhí)行上述代碼時,會產(chǎn)生以下結(jié)果 -
3083401324 3083401324 3083401324
Point destroyed
注意 - 理想情況下,應(yīng)該在單獨的文件中定義類,然后使用
import語句將其導(dǎo)入主程序文件。
在上面的例子中,假定Point類的定義包含在point.py中,并且其中沒有其他可執(zhí)行代碼。
#!/usr/bin/python3
import point
p1 = point.Point()
使用類繼承不用從頭開始構(gòu)建代碼,可以通過在新類名后面的括號中列出父類來從一個預(yù)先存在的類派生它來創(chuàng)建一個類。
子類繼承其父類的屬性,可以像子類中一樣定義和使用它們。子類也可以從父類代替代數(shù)據(jù)成員和方法。
語法
派生類被聲明為很像它們的父類; 然而,繼承的基類的列表在類名之后給出 -
class SubClassName (ParentClass1[, ParentClass2, ...]):
'Optional class documentation string'
class_suite
示例
#!/usr/bin/python3
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
當執(zhí)行上述代碼時,會產(chǎn)生以下結(jié)果 -
Calling child constructor
Calling child method
Calling parent method
Parent attribute : 200
以類似的方式,可以從多個父類來構(gòu)建一個新的類,如下所示:
class A: # define your class A
.....
class B: # define your calss B
.....
class C(A, B): # subclass of A and B
.....
可以使用issubclass()或isinstance()函數(shù)來檢查兩個類和實例之間的關(guān)系。
issubclass(sub,sup)布爾函數(shù)如果給定的子類sub確實是超類sup的子類返回True。isinstance(obj,Class)布爾函數(shù)如果obj是類Class的一個實例,或者是類的一個子類的實例則返回True。可以隨時重載父類的方法。 重載父方法的一個原因是:您可能希望在子類中使用特殊或不同的方法功能。
示例
#!/usr/bin/python3
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
當執(zhí)行上述代碼時,會產(chǎn)生以下結(jié)果 -
Calling child method
下表列出了可以在自己的類中覆蓋的一些通用方法 -
| 編號 | 方法 | 描述 | 調(diào)用示例 |
|---|---|---|---|
| 1 | __init__ ( self [,args...] ) |
構(gòu)造函數(shù)(帶任意可選參數(shù)) | obj = className(args) |
| 2 | __del__( self ) |
析構(gòu)函數(shù),刪除一個對象 | del obj |
| 3 | __repr__( self ) |
可評估求值的字符串表示 | repr(obj) |
| 4 | __str__( self ) |
可打印的字符串表示 | str(obj) |
| 5 | __cmp__ ( self, x ) |
對象比較 | cmp(obj, x) |
假設(shè)已經(jīng)創(chuàng)建了一個Vector類來表示二維向量。當使用加號(+)運算符執(zhí)行運算時,它們會發(fā)生什么? 很可能Python理解不了你想要做什么。
但是,可以在類中定義__add__方法來執(zhí)行向量加法,然后將按照期望行為那樣執(zhí)行加法運算 -
示例
#!/usr/bin/python3
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)
當執(zhí)行上述代碼時,會產(chǎn)生以下結(jié)果 -
Vector(7,8)
對象的屬性在類定義之外可能或不可見。需要使用雙下劃線前綴命名屬性,然后這些屬性將不會直接對外部可見。
示例
#!/usr/bin/python3
class JustCounter:
__secretCount = 0
def count(self):
self.__secretCount += 1
print (self.__secretCount)
counter = JustCounter()
counter.count()
counter.count()
print (counter.__secretCount)
當執(zhí)行上述代碼時,會產(chǎn)生以下結(jié)果 -
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通過內(nèi)部更改名稱來包含類名稱來保護這些成員。 可以訪問object._className__attrName等屬性。如果將最后一行替換為以下,那么它適用于 -
.........................
print (counter._JustCounter__secretCount)
當執(zhí)行上述代碼時,會產(chǎn)生以下結(jié)果 -
1
2
2