十一、PYTHON 面向對象編程

如果你沒有任何以往的經驗與面向對象(OO)編程,你可能想諮詢或至少某種教程的入門課程,所以,你必須掌握的基本概念.

然而,這裏是小推出的面向對象編程(OOP)給你帶來更好的學習速度:

面向對象術語

類: 用戶定義的一個對象,它定義了一套類的任何對象的屬性特點的原型。屬性數據成員(類變量和實例變量)和方法,通過點符號訪問.

類變量: 一個類的所有實例共享變量。類變量被定義在一個類以外的任何類的方法。不作爲類變量經常作爲實例變量.

數據成員: A類變量或實例變量持有一個類和它的對象的相關數據.

函數重載: 分配到一個特定功能的多個行爲。執行的操作,因涉及的對象(參數)的類型。

實例變量: 一個方法內定義的變量只屬於一類的當前實例.

繼承 : 傳遞類的特點是從它派生的其他類.

實例: 某個類的一個單獨的對象。例如,一個對象obj屬於類Circle,是類Circle的一個實例.

實例化 : 創建一個類的實例.

方法 : 一個是定義在類定義中的一種特殊功能.

對象: 這是由它的類定義一個數據結構的一個唯一的實例。對象包括數據成員(類變量和實例變量)和方法.

運算符重載: 多個函數分配到一個特定的運算符.

創建類:

類的語句創建一個新的類定義。類名緊跟在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就會調用.

  • 你聲明異常,每個方法的第一個參數是自我的正常功能等其他類的方法。 Python中添加自參數到你的列表,當你調用的方法,你不需要包括它.

創建實例對象:

要創建一個類的實例,調用類,使用類的名稱,並通過在其__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]) : 訪問對象的屬性.

  • The hasattr(obj,name) : 檢查是否存在一個屬性.

  • The setattr(obj,name,value) : 設置一個屬性。如果屬性不存在,然後將它創建.

  • The 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__ : 一個基類包含在其發生在基類列表中的順序可能是空的元組,.

對於上面的類,讓我們嘗試訪問所有這些屬性:

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':, 'empCount': 2, 
'displayEmployee':, 
'__doc__': 'Common base class for all employees', 
'__init__':}

銷燬對象(垃圾收集):

Python中刪除不必要的對象(內置類型或類的實例),自動釋放內存空間。其中Python的定期回收不再使用的內存塊的過程被稱爲垃圾收集.

Python的垃圾收集器運行程序執行過程中被觸發時,一個對象的引用計數達到零。別名對象的引用計數的變化,指出它的變化:

一個對象的引用計數增加時,它分配一個新的名稱或放置在一個容器(列表,元組或字典)。該對象的引用計數減少,其引用被重新分配,或者其引用超出範圍時,它用del刪除。當一個對象的引用計數達到零時,Python它會自動收集.


a = 40      # Create objectb = a       # Increase ref. count  ofc = [b]     # Increase ref. count  ofdel a       # Decrease ref. count  ofb = 100     # Decrease ref. count  ofc[0] = -1   # Decrease ref. count  of


你通常不會注意到,當垃圾收集器會破壞一個孤立的實例,並回收其空間。但是,一個類可以實現特殊方法__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語句導入。 - 更多細節,請查看Python的導入模塊和類模塊章節.

類的繼承:

而非從頭開始,你可以創建一個類,它從一個已經存在的類派生新類的名稱後括號中的父類列出:

子類繼承它的父類的屬性,如果他們在子類中定義,你可以使用這些屬性。子類也可以覆蓋從父數據成員和方法.

語法:

派生類的聲明,就像他們的父類;但是繼承的基類列表類名後:

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 calss B
.....

class C(A, B):   # subclass of A and B
.....

您可以使用issubclass()或isinstance()函數來檢查一個關係兩個類和實例:

  • issubclass(sub, sup) 布爾函數返回true,如果給定的子類subis的確是一個超類的子類sup.

  • isinstance(obj, Class) 布爾函數返回true,如果obj是一個Class類的實例,或者是一類的子類的一個實例.

重寫方法:

你總是可以覆蓋父類方法。覆蓋父方法的原因之一是因爲你可能想在你的子類特殊或不同的功能.

例如:

#!/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

相應重載方法:

下表列出了一些通用的功能,你可以在自己的類覆蓋:

SN 方法、描述和簡單調用
1 __init__ ( self [,args...] )
Constructor (with any optional arguments)
Sample Call : obj = className(args)
2 __del__( self )
Destructor, deletes an object
Sample Call : dell obj
3 __repr__( self )
Evaluatable string representation
Sample Call : repr(obj)
4 __str__( self )
Printable string representation
Sample Call : str(obj)
5 __cmp__ ( self, x )
Object comparison
Sample Call : 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

This would produce following result:

Vector(7,8)

Data Hiding:

An object's attributes may or may not be visible outside the class definition. For these cases, you can name attributes with a double underscore prefix, and those attributes will not be directly visible to outsiders:

Example:

#!/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, inprint counter.__secretCountAttributeError: JustCounter instance has no attribute '__secretCount'

你可以通過 object._className__attrName的形式來訪問.

如果你替換最後一行如下:

.........................
print counter._JustCounter__secretCount

最終的結果將會是:

1
2
2
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章