1. 程式人生 > 其它 >Python類和物件學習小記

Python類和物件學習小記

由於某人的需求(?),我開始學起了Python的面向物件程式設計。因為以前學習過 C++ 的類和物件,接下來我儘可能從 C++ 的類和物件語法角度來快速過這部分內容。過載和多型這部分內容應該用不到,就沒看了。

例程出處可見 Python 面向物件 | 菜鳥教程

目錄

例子1:基本知識

#!/usr/bin/python
# -*- coding: UTF-8 -*-
 
class Employee:
   '所有員工的基類'
   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
      
"建立 Employee 類的第一個物件"
emp1 = Employee("Zara", 2000)
"建立 Employee 類的第二個物件"
emp2 = Employee("Manni", 5000)
emp1.displayEmployee()
emp2.displayEmployee()
print "Total Employee %d" % Employee.empCount
  • class Employee: '所有員工的基類':類文件字串,相當於註釋,但不是真的註釋,而是作為了程式碼的一部分,方便閱讀程式碼
  • empCount:應視為C++的靜態成員變數(對,是加修飾詞 static 的那種,真的不是普通成員變數,普通成員變數都在“建構函式”中就已經“宣告”了。注意,因為python的語法沒那麼嚴格,不需要宣告變數,別問我為什麼python是這個鬼樣子)
  • def __init__(self, name, salary):可視為建構函式
  • def displayCount(self):類的方法,可視為成員函式
  • self:相當於C++中的 this 指標,實際上也可以換成別的名字。類的方法必須都加上這個引數,用於指代自己
  • 建立例項(這裡沒什麼好說的,例項化物件罷了):
"建立 Employee 類的第一個物件"
emp1 = Employee("Zara", 2000)
"建立 Employee 類的第二個物件"
emp2 = Employee("Manni", 5000)
  • 訪問屬性及呼叫方法(訪問成員變數、呼叫成員函式):
emp1.displayEmployee()
emp2.displayEmployee()
print "Total Employee %d" % Employee.empCount
  • 接下來的例子很有意思了,因為Python中可以在任意地方任意新增屬性(成員變數),但是C++不能:
emp1.age = 7  # 新增一個 'age' 屬性
emp1.age = 8  # 修改 'age' 屬性
del emp1.age  # 刪除 'age' 屬性

因此,需要引入一個訪問屬性的機制,以方便監控屬性:

hasattr(emp1, 'age')    # 如果存在 'age' 屬性返回 True。
getattr(emp1, 'age')    # 返回 'age' 屬性的值
setattr(emp1, 'age', 8) # 新增屬性 'age' 值為 8
delattr(emp1, 'age')    # 刪除屬性 'age'

例子2:內建屬性

接下來的例子確實很有Python的味道。。。

#!/usr/bin/python
# -*- coding: UTF-8 -*-
 
class Employee:
   '所有員工的基類'
   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__

Python的內建類屬性:

  • __name__: 類名
  • __bases__ : 類的所有父類構成元素(包含了一個由所有父類組成的元組)。這個可以直接檢視被繼承的類有哪些,比C++方便多了
  • __module__: 類定義所在的模組(類的全名是'__main__.className',如果類位於一個匯入模組mymod中,那麼className.__module__ 等於 mymod)
  • __doc__ : 類的文件字串

例子3:物件銷燬

這個例子涉及物件的銷燬。

#!/usr/bin/python
# -*- coding: UTF-8 -*-
 
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, "銷燬"
 
pt1 = Point()
pt2 = pt1
pt3 = pt1
print id(pt1), id(pt2), id(pt3) # 列印物件的id
del pt1
del pt2
del pt3

輸出結果:

3083401324 3083401324 3083401324
Point 銷燬
  • def __del__(self):相當於C++中的解構函式
  • 物件的id可以簡單理解為物件的“地址”

例子4:類的繼承

以下幾部分內容與C++的習慣大有不同,雖然核心是相同的。注意其區別。

#!/usr/bin/python
# -*- coding: UTF-8 -*-
 
class Parent:        # 定義父類
   parentAttr = 100
   def __init__(self):
      print "呼叫父類建構函式"
 
   def parentMethod(self):
      print '呼叫父類方法'
 
   def setAttr(self, attr):
      Parent.parentAttr = attr
 
   def getAttr(self):
      print "父類屬性 :", Parent.parentAttr
 
class Child(Parent): # 定義子類
   def __init__(self):
      print "呼叫子類構造方法"
 
   def childMethod(self):
      print '呼叫子類方法'
 
c = Child()          # 例項化子類
c.childMethod()      # 呼叫子類的方法
c.parentMethod()     # 呼叫父類方法
c.setAttr(200)       # 再次呼叫父類的方法 - 設定屬性值
c.getAttr()          # 再次呼叫父類的方法 - 獲取屬性值

輸出:

呼叫子類構造方法
呼叫子類方法
呼叫父類方法
父類屬性 : 200
  • class C(A, B): # 繼承類 A 和 B
  • 例項化子類,只會呼叫子類的構造方法(對應C++建構函式)
  • 如果在子類中需要父類的構造方法就需要顯式的呼叫父類的構造方法,或者不重寫父類的構造方法(意思就是子類不寫建構函式就完事了)

重要注意!如果要繼承父類的構造方法,可以使用 super 關鍵字:

super(子類,self).__init__(引數1,引數2,....)
或
父類名稱.__init__(self,引數1,引數2,...)

例子:

class Father(object):
    def __init__(self, name):
        self.name=name
        print ( "name: %s" %( self.name))
    def getName(self):
        return 'Father ' + self.name
 
class Son(Father):
    def __init__(self, name):
        super(Son, self).__init__(name)
        print ("hi")
        self.name =  name
    def getName(self):
        return 'Son '+self.name
 
if __name__=='__main__':
    son=Son('runoob')
    print ( son.getName() )

輸出(先呼叫父類方法,再呼叫子類方法):

name: runoob
hi
Son runoob

例子5:訪問許可權

#!/usr/bin/python
# -*- coding: UTF-8 -*-
 
class JustCounter:
    __secretCount = 0  # 私有變數,加了兩個下劃線在開頭
    publicCount = 0    # 公開變數
 
    def count(self):
        self.__secretCount += 1
        self.publicCount += 1
        print self.__secretCount
 
counter = JustCounter()
counter.count()
counter.count()
print counter.publicCount
print counter.__secretCount  # 報錯,例項不能訪問私有變數
  • 私有屬性(私有成員變數):
__private_attrs:兩個下劃線開頭加在屬性名字開頭,表示為私有屬性
類內部使用:self.__private_attrs
  • 私有方法(私有成員函式):
__private_method:兩個下劃線開頭加在方法名字開頭,表示為私有方法
類的內部呼叫:self.__private_methods

補充:單下劃線、雙下劃線、頭尾雙下劃線

  • __foo__: 定義的是特殊方法,一般是系統定義名字 ,類似 __init__() 之類的。

  • _foo: 以單下劃線開頭的表示的是 protected 型別的變數,即保護型別只能允許其本身與子類進行訪問,不能用於 from module import * (保護屬性在 C++ 中應該很熟悉了,父類子類都能訪問,但是外部不能訪問;私有屬性是父類自己能訪問,繼承的子類和外部不能訪問)

  • __foo: 雙下劃線的表示的是私有型別(private)的變數, 只能是允許這個類本身進行訪問了。

好了,就看到這吧。

---EOF---