1. 程式人生 > >Python 類與面向物件

Python 類與面向物件

Python 類與面向物件

1,程式 = 指令 + 資料
·程式碼可以選擇以指令為核心或以資料為核心進行編寫

2,兩種範型
·以指令為核心:圍繞"正在發生什麼"進行編寫
1)面向過程程式設計:程式具有一系列性步驟;主體思想是程式碼作用於資料

 ·以資料為核心:圍繞"將影響誰"進行編寫
       1)面向物件程式設計(OOP):圍繞資料及為資料嚴格定義的介面來組織程式用資料控制對程式碼的訪問。

3,所有程式語言的最終目的都是提供一種抽象方法
1)在機器模型(“解空間"或"方案空間”)與實際解決的問題模型(“問題空間”)之間,程式設計師必須建立一種聯絡。

   ·面向過程:程式 = 演算法 + 資料結構
   ·面向物件:將問題空間中的元素以及它們在解空間中的表示物抽象為物件,並允許通過問題來描述問題而不是方案
          1)可以把物件想象成一種新型變數,它儲存著資料,但可以對自身的資料執行操作

4,型別由狀態集合(資料)和轉換這些狀態的操作集合組成
1,類抽象
類:定義了被多個同一型別物件共享的結構和行為(資料和程式碼)
類的資料和程式碼:即類的成員
資料:成員變數或例項變數
成員方法:簡稱為方法,是操作資料的程式碼,用於定義如何使用成員變數;因此以個類的行為和介面是通過方法來定義的
2,方法和變數:
· 私有:內部使用
· 公共:外部可見

面向物件的程式設計方法
1,所有東西都是物件
2,程式是一大堆物件的組合
·通過訊息傳遞,各物件知道自己該做什麼
·訊息:即呼叫請求,它呼叫的是從屬於目標物件的一個方法
3,每個物件都有自己的儲存空間,並可容納其它物件
·通過封裝現有物件,可以製作成新型物件
4,每個物件都屬於某一型別
·型別,也即使類
·物件是類的是咧
·類的一個重要特性為"能發什麼樣的訊息給它"
5,同一個類的所有物件都能接收相同的訊息

物件的介面:
1,定義一個類後,可以根據需要例項化出多個物件
2,如何利用物件完成真正有用的工作?
1)必須有一種辦法能向物件發出請求,令其做一些事情
2)每個物件僅能接受特定的請求
·能向物件傳送的請求由其"介面"進行定義
·物件的"型別"或"類"則規定了它的介面形式

型別名 light

介面  on()
      off()
      brighten()
      dim()

類:將同一種具體物事的共同特性抽象出來的表現
狀態和轉換這些狀態的操作
資料:狀態
變數:就是屬性
方法:操作
函式:操作變數引用的資料的程式碼

方法是類的組成部分。

類間關係
1,依賴(“uses -a”)
· 一個類的方法操作另一個類的物件
2,聚合(“has -a”)
·類A 的物件包含類B的物件
3,繼承(“is -a”)
·描述特殊與一般關係

面向物件程式設計的原則
1,面向物件的模型機制有3個原則:封裝,繼承及多型
2,封裝(Encapsulation)
·隱藏實現方案細節
·將程式碼及其處理的資料繫結在一起的一種程式設計機制,用於保證程式和資料不受外部干擾且不會被誤用!

3,繼承(Inheritance)
·一個物件獲得另一個物件屬性的過程;用於實現按層分類的概念
·一個深度繼承的子類繼承了類層次中它的每個祖先的所有屬性
·超類,基類,父類
·子類,派生派

4,多型性(Ploymorphism)
·允許一個藉口被多個通用的類動作使用的特性,具體使用哪個動作與應用場合相關
·“一個介面,多個方法”
1),用於為一組相關的動作設計一個通用的介面,以降低程式複雜性

5,面向物件程式設計的3個原則
1) 類是一種資料結構,可用於建立例項
·一般情況下,類封裝了資料和可用於該資料的方法
2) Python類是一個可呼叫物件,即類物件
3) Python2.2之後,類是一種自定義型別,而例項則是宣告某個自定義型別的變數
4) 例項初始化
·通過呼叫類來建立例項
instance = ClassName(args…)
·類在例項化時可以使用_init_和_del_兩個特殊的方法
class class_name
例項物件
類儲存的物件叫類物件!
類儲存被例項化後的物件叫例項物件!

Python 中建立類
1,Python 使用class關鍵字建立類,語法格式如下
·class ClassName(bases):
1)‘class documentation string’
2) class_suite
·超類是一個或多個用於繼承的父類的集合
·類體可以包含:宣告語句,類成員定義,資料屬性,方法
·注意:
1)如果不存在繼承關係,ClassName後面的"(bases)"可以不提供
2)類文件為可選
2,class語句的一般形式
·class ClassName(bases):
1)data = value → 定義資料屬性
2)def method(self,…): → 定義方法屬性
·self.member = value

建立類:例如
class TestClass():
pass
將類轉為例項:例如
obj1 = TestClass()

也就是說將類物件賦值傳遞給一個引數,進行例項化

Python中,class語句類似def ,是可執行程式碼;直到執行clas語句後類才會存在

 >>> class FirstClass:
           spam = 30          類資料屬性
           def display(self): 類方法,屬於可呼叫的屬性
               print self.spam

 >>> x = FirstClass()
 >>> x.display()   方法呼叫
 30

如下例子:
In [28]: class thirdclass():
…: data = ‘hello ThirdClass’
…: def setdata(self,x):
…: self.str1 = x
…: print self.str1
…: def printdata(self):
…: print self.str1
…:

 需要 test = thirdclass()
      test.setdata() 賦值
      然後輸出test.printdata、test.setdata,test.str1才能正常輸出

Python類方法及呼叫
1,例項(物件)通常包含屬性
·可呼叫的屬性:方法
object.method()
·資料屬性
在OOP中,例項就像是帶有"資料"的記錄,而類是處理這些記錄的"程式"

2,通過例項呼叫方法相當於呼叫所屬類的方法來處理當前例項
·類似instance.method(args…)會被自動轉換為
class.method(instance,args…)
1)如前面的例子,x.display()會被自動轉換為FirstClass.display(x),即呼叫類的方法來處理例項x
3,因此,類中每個方法必須具有self引數,它隱含當前例項之意
4,在方法內對self屬性做賦值運算會產生每個例項自己的屬性
5,Python規定,沒有例項,方法不允許被呼叫,此即為"繫結"

Python類和例項的屬性

1,class語句中的賦值語句會建立類屬性,如前面例子中的spam
2, 在類方法中對傳給方法的特殊引數self進行賦值會建立例項屬性

Python構造器
1,建立例項時,Python會自動呼叫類中的_init_方法,以隱形地為例項提供屬性
2,如果類中沒有定義_init_方法,例項建立之初僅是一個簡單的名稱空間

  例如:
      >>> class Myclass():
                gender = 'Male'
                def  _init_(self,who):
                      self.name = who

      >>> x = Myclass('Tom')
      >>> y = Myclass('jerry')
      >>> x.gender,x.name
         ('Male','tom')
      >>> y.gender,y.name
         ('Male','jerry')

也就是說Python構造器,可以直接通過類進行賦值,而不需要從def 定義的引數先賦值後,在進行呼叫!

Python 析構器(解構器)
def def(self):

類的特殊屬性
1,可以使用類的_dict_字典屬性或Python內建的dir()函式來獲取類的屬性

dir(MyClass)
[‘doc’,‘init’,‘module’,‘gender’]

MyClass.dict

C.name 類C 的名字(字串)
C.doc 類C 的文件字串
C.bases 類C 的所有父類構成的元組
C.dict 類C 的屬性
C.module 類C 定義所在的模組(1.5版本新增)
C.class 例項C 對應的類(僅新式類中)

例項屬性

1,例項僅擁有資料屬性(嚴格意義上來說,方法是類屬性)
·通常通過構造器"init"為例項提供屬性
·這些資料屬性獨立於其它例項或類
·例項釋放事時,其屬性也將被清除
2,內建函式dir()或例項的特殊屬性__dict__可用於檢視例項屬性

3,例項的特殊屬性

Python類方法中可用的變數

1,方法的可用變數
·例項變數:指定變數名稱及例項自身進行引用
self.變數名
self.name = who 例項變數
2,區域性變數:方法內部建立的變數,可直接使用
def print(self) 為區域性變數
3,類變數(也稱靜態變數):通過指定變數名與類名進行引用
類名。變數名
gender = ‘Male’ 類變數
4,全域性變數:直接使用

In [58]: class c1():
…: d1 = ‘hello c1 class’
…: def init(self,x):
…: self.insdata = x

例子:
i1 = c1(50)
i1.d1 輸出值 hello c1 class
i1.insdata 輸出值 50

     i2 = c1(100)
     i2.d1     輸出值 hello c1 class
     i2.insdata 輸出值 100

     i1.d1 = 'heihei' 那麼i1的呼叫變數的儲存位置改變
     i1.d1    輸出值 heihei

     而i2.d1  輸出值 hello c1 class
     
     c1.d1 = 'how old are you'
    
     i1.d1 輸出值 heihei
     i2.d1 輸出值 how old are you 

繼承
繼承描述了基類的屬性如何"遺傳"給派生類
1,子類可以繼承它的基類的任何屬性,包括資料屬性和方法
2,一個未指定基類的類,其預設有一個名為object的基類
3,Python 允許多重繼承

建立子類
1,建立子類時,只需要在類名後跟一個或從其中派生的父類
2,class SubClassName(ParentClass1[,ParentClass2,…])
·‘optional class documentation string’
·class_suite

寫法如下:
class parent(object):
gender = ‘Male’
def init(self,who):
self.name = who

        class CClass(parent):
              def displayInfo(self,who):
                  print self.gender,self.name

Python 類的繼承和屬性搜尋

Python 中幾乎所有屬性的獲取都可以使用"object.attribute(物件.屬性)"的格式
1,不過,此表示式會在Python中啟動搜尋–搜尋連續的樹

class 語句會產生一個類物件,對class的呼叫會建立例項,例項自動連線至建立了這些例項的類

 2,類連結至其超類的方式
      ·將超類列在類頭部的括號內,其從左至右的順序會決定樹中的次序
      ·由下至上,由左至右

繼承方法專用化

 1,繼承會先在子類尋找變數名,然後才查詢超類,因此,子類可以對超類的屬性重新定義來取代繼承而來的行為
      ·子類可以完全取代從超類繼承而來的屬性
      ·也可以通過已覆蓋的方法回撥超類來擴充套件超類的方法

    1)子類對超類的屬性重新定義來取代繼承而來的屬性
           例如
         >>>class  ParClass(object):
                  def setInfo(self,sex='Male'):
                      self.gender = sex
         >>>class  ChiClass(ParClass):
                  def setInfo(self,who):
                      self.name = who
          
          因為子類中用相同的方法定義了setInfo,所以從而覆蓋了父類的setInfo。
                 y = ParClass()
                 y.setInfo('Tom')
                 y.gender  輸出  Tom
                     此種方法是可以進行對父類進行呼叫的!

    2)通過已覆蓋的方法回撥超類來擴充套件超類的方法
           例如
          >>>class ParClass(object):
                  def setInfo(self,sex='Male'):
                         self.gender = sex
          >>>class ChiClass(ParClass):
                  def setInfo(self,who):
                         self.name = who
                         ParClass.setInfo(self)
           其中ParClass.setInfo 是對父類(超類)進行了回撥,或者說來擴充套件超類! 

類、例項和其它物件的內建函式
1,issubclass()
·布林函式,判斷一個類是否由另一個類派生(子類),語法:
issubclass(sub,sup)
2,isinstance()
·布林函式,判斷一個物件是否是給定類的例項,語法:
isinstance(obj1,class_obj2)
3,hasattr()
·布林函式,判斷一個物件是否擁有指定的屬性,語法:
hasattr(obj,‘attr’)
·同類函式還有getattr(),setattr()和delattr()
4,super()
·在子類中找出其父類以便於呼叫其屬性
·一般情況下僅能採用非繫結方式呼叫祖先類方法
·而super()可用於傳入例項或型別物件,語法:
super(type[,obj])

運算子過載

運算子過載是指在方法中攔截內建的操作–當類的例項出現在內建操作中,Python會自動呼叫自定義的方法,並且返回自定義方法的操作結果

1,運算子過載讓類攔截常規的Python運算
·類可過載所有Python表示式運算子
·類也可過載列印,函式呼叫,屬性點號運算等內建運算
2,過載使類例項的行為像內建型別。
3,過載通過提供特殊名稱的類方法實現。

運算子過載並非必需,並且通常也不是預設的

基於特殊的方法定製類

除了__init__和__del__之外,Python類支援使用許多的特殊方法

1,特殊方法都以雙下劃線開頭和結尾,有些特殊方法有預設行為,沒有預設行為的是為了留到需要的時候再實現
2,這些特殊方法是Python中用來擴充類的強大工具,它們可以實現
·模擬標準型別
·過載操作符
3,特殊方法允許類通過過載標準操作符+,*,甚至包括分段下標及對映操作[]來模擬標準型別