欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Python面向對象程序設計OOP入門教程【類,實例,繼承,重載等】

 更新時間:2019年01月05日 12:01:08   作者:KLeonard  
這篇文章主要介紹了Python面向對象程序設計OOP入門教程,較為詳細的分析了Python面向對象類,實例,繼承,重載等相關概念與使用技巧,需要的朋友可以參考下

本文實例講述了Python面向對象程序設計OOP。分享給大家供大家參考,具體如下:

類是Python所提供的最有用的的工具之一。合理使用時,類可以大量減少開發(fā)的時間。類也在流行的Python工具中使用,例如,tkinter GUI API。

為何使用類

與面向對象的Java一樣,類是對現實世界的一種抽象。

從更具體的程序設計觀點來看,類是Python的程序組成單元,就像函數和模塊一樣:類是封裝邏輯和數據的另一種方式。實際上,類也定義新的命名空間,在很大程度上就像模塊。但是類有三個重要的獨到之處,使其在建立對象時更為有用。

1.多重實例

類基本上就是產生對象的工廠。每次調用一個類,就會產生一個有獨立命名空間的新對象。每個又類產生的對象都能讀取類的屬性,并獲得自己的命名空間來儲存數據,這些數據對于每個對象來說都不同。

2.通過繼承進行定制

類也支持OOP的繼承的概念。我們可以在類的外部重新定義其屬性從而擴充這個類。

3.運算符重載

通過提供特定的協(xié)議方法,類可以定義對象來響應在內置類型上的幾種運算。例如,通過類創(chuàng)建的對象可以進行切片,級聯(lián)和索引等運算。Python提供了一些可以由類使用的鉤子,從而能夠中斷并實現任何的內置類型運算。

Python的類與Java類似,所以關于繼承、屬性和方法以及類和實例的基礎知識在這里不再贅述。直接介紹語法內容。

類產生多個實例對象

【OOP模型中的兩種對象:類對象和實例對象】

類對象提供默認行為,是實例對象的工廠。實例對象是程序處理的實際對象:各自都有獨立的命名空間,但是繼承(可自動存?。﹦?chuàng)建該實例的類中的變量名。類對象來自于語句,而實例來自于調用。每次調用一個類,就會得到這個類的新的實例。

【類對象提供默認行為】

執(zhí)行class語句,就會得到類對象。以下是Python類的主要特性:
1.class語句創(chuàng)建類對象并將其賦值給變量名。就像函數def語句,Python class語句也是可執(zhí)行語句,執(zhí)行時,會產生新的類對象,并將其賦值給class頭部的變量名。此外,就像def應用,class語句一般是在其所在文件導入時執(zhí)行的。

2.class語句內的賦值語句會創(chuàng)建類的屬性。class語句內的頂層的賦值語句會產生類對象中的屬性。從技術角度講,class語句的作用域會變成類對象的屬性的命名空間,就像模塊的全局作用域一樣。執(zhí)行class語句后,類的屬性可由變量名點號運算獲取object.name。

3.類屬性提供對象的狀態(tài)和行為。類對象的屬性記錄狀態(tài)信息和行為,可由這個類創(chuàng)建的所有實例共享。位于類中的函數def語句會生成方法,方法將會處理實例。

【實例對象是具體元素】

當調用類對象時,我們得到了實例對象。以下是類的實例內含的重點概要。

1.像函數那樣調用類對象會創(chuàng)建新的實例對象。實例代表了程序領域中的具體元素。

2.每個實例對象繼承類的屬性并獲得了自己的命名空間。由類所創(chuàng)建的實例對象是新的命名空間。一開始是空的,但是會繼承創(chuàng)建該實例的類對象內的屬性。

3.在方法內對self屬性做賦值運算會產生每個實例自己的屬性。在類方法函數內,第一個參數(self)會引用正處理的實例對象。對self的屬性做賦值運算,會創(chuàng)建或修改實例內的數據,而不是類的數據。

第一個例子

首先定義一個名為FirstClass的類,通過交互模式運行Python class 語句。

>>> class FirstClass:
 def setdata(self,value):
 self.data = value
 def display(self):
 print(self.data)

這里是在交互模式下工作,但一般來說,這種語句應該是當其所在的模塊文件導入時運行的。就像通過def建立的函數,這個類在Python抵達并執(zhí)行語句前是不會存在的。

就像所有的復合語句一樣,class開頭一行會列出類的名稱,后面再接一個或多個內嵌并且縮進的語句的主體。

就像之前學過的,def其實是賦值運算。在這里把函數對象賦值給變量名setdata,而display位于class語句范圍內,因此會產生附加在類上的屬性:FirstClass.setdataFirstClass.display。事實上,在類嵌套的代碼塊中頂層的賦值的任何變量名,都會變成類的屬性。

位于類中的函數通常稱為方法。方法時普通def,支持先去學過的函數的所有內容。在方法函數中,調用時,第一個參數(self)自動接收隱含的實例對象:調用的主體。下面建立這個類兩個實例:

>>> x = FirstClass()
>>> y = FirstClass()

以此方式調用類時,【注意后面有小括號】,會產生實例對象。確切的講,此時有三個對象:兩個實例和一個類。

這兩個實例一開始是空的,但是它們被連接到創(chuàng)建它們的類。如果對實例以及類對象內的屬性名稱進行點號運算,Python會通過繼承搜索從類取得變量名。

>>> x.setdata('King Arthur')
>>> y.setdata(3.14159)

x或y本身都沒有setdata屬性,為了尋找這個屬性,Python會順著實例到類的連接搜索。而這就是所謂的Python的繼承:繼承是在屬性點號運算時發(fā)生的,而且只與查找連接對象內的變量名有關。

在FirstClass的setdata函數中,傳入的值會賦給self.data。在方法中,self(按慣例,這是最左側參數的名稱)會自動引用正在處理的實例(x或y),所以賦值語句會把值儲存在實例的命名空間,而不是類的命名空間。

因為類會產生多個實例,方法必須經過self參數才能獲取正在處理的實例。當調用類的display方法來打印self.data時,會發(fā)現每個實例的值都不同。另外,變量名display在x和y之內都相同,因為它是來自于類的:

>>> x.display()
King Arthur
>>> y.display()
3.14159

注意:在每個實例內的data成員儲存了不同對象類型(字符串和浮點數)。就像Python中的其他事物,實例屬性并沒有聲明。首次賦值后,實例就會存在,就像簡單的變量。事實上,如果在調用setdata之前,就對某一實例調用display,則會觸發(fā)未定義變量名的錯誤:data屬性以setdata方法賦值前,是不會在內存中存在的。

我們可以在類的內部或外部修改實例屬性。在類內時,通過方法對self進行賦值運算,而在類外時,則可以通過對實例對象進行賦值運算:

>>> x.data = 'New value'
>>> x.display()
New value

雖然比較少見,通過在類方法函數外對變量名進行賦值運算,我們甚至可以在實例命名空間內產生全新的屬性:

>>> x.anothername = 'spam'

這里會增加一個名為anothername的新屬性,實例對象x的任何類方法都可以使用它。

不過,類通常是通過self參數進行賦值運算從而建立實例的所有屬性的。

類通過繼承進行定制

除了作為工廠來生成多個實例對象之外,類也可以引入新組件(子類)來進行修改,而不對現有組件進行原地的修改。由類產生的實例對象會繼承該類的屬性。

在Python中,實例從類中繼承,而類繼承于超類。以下是屬性繼承機制的核心觀點:

1.超類列在了類開頭的括號中。含有繼承的類稱為子類,而子類所繼承的類就是其超類。

2.類從其超類中繼承屬性。就像實例繼承其類中所定義的屬性名一樣,類也會繼承其超類中定義的所有屬性名稱。當讀取屬性時,如果它不存在于子類中,Python會自動搜索這個屬性。

3.每個object.attribute都會開啟新的獨立搜索。

4.邏輯的修改是通過創(chuàng)建子類,而不是修改超類。在樹中層次較低的子類中重新定義超類的變量名,子類就可以取代并定制所繼承的行為。

第二個例子

下個例子建立在上一個例子的基礎之上。首先,定義一個新的類SecondClass,繼承FirstClass所有變量名,并提供自己的一個變量名。

>>> class secondClass(FirstClass):
 def display(self):
 print('Current value = " %s "'%self.data)

SecondClass定義display方法以不同格式打印。定義一個和FirstClass中的屬性同名的屬性,SecondClass有效地取代其超類內的display屬性。因為繼承搜索會從實例向上進行,之后到子類,然后到超類,直到所找到的屬性名稱首次出現為止。

有時候,我們把這種在樹中較低處發(fā)生的重新定義的、取代屬性的動作稱為【重載】。結果就是,SecondClass改變了display的行為,把FirstClass特定化了。另外,SecondClass(以及其任何實例)依然會繼承FirstClass的setdata方法:

>>> z = SecondClass()
>>> z.setdata(42)
>>> z.display()
Current value = " 42 "

這里有一個和OOP相關的很重要的事情要留意:SecondClass引入的專有化完全是在FirstClass外部完成的。也就是說,不影響當前存在的或未來的FirstClass對象,就像上一個例子中的x:

>>> x.display()
New value

類是模塊內的屬性

類的名稱沒有什么神奇之處。當class語句執(zhí)行時,這只是賦值給對象的變量,而對象可以用任何普通表達式引用。

例如,如果FirstClass是寫在模塊文件內,而不是在交互模式下輸入的,就可將其導入,在類開頭的那行可以正常地使用它的名稱。

from modulename import FirstClass
class SecondClass(FirstClass):
 def display(self):...

或者,其等效寫法:

import modulename
class SecondClass(module.FirstClass):
 def display():...

像其他事物一樣,類名稱總是存在于模塊中。每個模塊可以任意混合任意數量的變量、函數以及類。文件food.py示例如下:

#food.py
var = 1
def func():
 ...
class spam:
 ...
class ham:
 ...
class eggs:
 ...

如果模塊和類碰巧有相同的名稱,也是如此。文件person.py,寫法如下:

class person:
 ...

需要像往常一樣通過模塊獲取類:

import person
x = person.person()

person.person()指的是person模塊內的person類。只寫person只會取得模塊,而不是類,除非使用from語句。

from person import person
x = person()

Python的通用慣例之處,類名應該以一個大寫字母開頭,以使得他們更為清晰:

import person
x = person.Person()

類可以截獲Python運算符:運算符重載

運算符重載就是讓類寫成的對象,可以截獲并響應用在內置類型上的運算:加法、切片、打印和點號運算等。

因為運算符重載,可以讓我們自己的對象行為就像內置對象那樣,這可促進對象接口更為一致并更易于學習,而且可讓類對象由預期的內置類型接口的代碼處理。以下是重載運算符主要概念的概要:

1.以雙下劃線命名的方法(__X__)是特殊鉤子。Python運算符重載的實現是提供特殊命名的方法來攔截運算。Python語言替每種運算和特殊命名的方法之間,定義了固定不變的映射關系。

2.當實例出現在內置運算時,這類方法會自動調用。例如,如果實例對象繼承了__add__方法,當對象出現在+表達式內時,該方法就會調用。該方法的返回值變成相應表達式的結果。

3.類可覆蓋多數內置類型運算。有幾十種特殊運算符重載的方法的名稱,幾乎可以截獲并實現內置類型的所有運算。它不僅包括了表達式,而且像打印和對象建立這類基本運算也包括在內。

4.運算符覆蓋方法沒有默認值,而且也不需要。如果類沒有定義或繼承運算符重載方法,就是說相應的運算在類實例中并不支持。例如,如果沒有__add__,+表達式就會引發(fā)異常。

5.運算符可讓類與Python的對象模型相集成。

【不過,要注意的是,運算符重載是可選的功能,一般的應用程序開發(fā)并不需要,除非真的有特殊的需求需要模仿內置類型接口?!?/p>

第三個例子

這一次,要定義SecondClass的子類,實現三個特殊名稱的屬性,讓Python自動進行調用:

1.當新的實例構造時,會調用__init__(self是新的ThirdClass對象)
2.當ThirdClass實例出現在+表達式中時,則會調用__add__。
3.當打印一個對象的時候(從技術上講,當通過str內置函數或者其Python內部的等價形式來將其轉換為打印字符串的時候),運行__str__

新的子類也定義了一個常規(guī)命名的方法,叫做mul,它在原處修改該實例的對象。如下是一個新的子類:

>>> class ThirdClass(SecondClass):
 def __init__(self,value):
 self.data = value
 def __add__(self,other):
 return ThirdClass(self.data+other)
 def __str__(self):
 return '[ThirdClass:%s]'%self.data
 def mul(self,other):
 self.data*=other
>>>
>>> a = ThirdClass('abc')
>>> a.display()
Current value = " abc "
>>> print(a)
[ThirdClass:abc]
>>> b = a + 'xyz'
>>> b.display()
Current value = " abcxyz "
>>> a.mul(3)
>>> print(a)
[ThirdClass:abcabcabc]

ThirdClass是一個SecondClass對象,所以其實例會繼承SecondClass的display方法。但是,ThirdClass生成的調用現在會傳遞一個參數(例如,‘abc'),這是傳給__init__構造函數內的參數value的,并將其值賦給self.data。直接效果就是,ThirdClass計劃在構建時自動設置data屬性,而不是在構建之后請求setdata調用。

此外,ThirdClass對象現在可以出現在+表達式和print調用中。對于+,Python把左側的實例對象傳給__add__中的self參數,而把右邊的值傳給other。__add__返回的內容成為+表達式的結果。對于print,Python把要打印的對象傳遞給__str__中的self;該方法返回的字符串看作是對象的打印字符串。使用__str__,我們可以用一個常規(guī)的print來顯示該類的對象,而不是調用特殊的display方法。

__init__、__add__和__str__這樣的特殊命名的方法會由子類和實例繼承,就像這個類中賦值的其他變量名。Python通常會自動調用,但偶爾也能由程序代碼調用。

【注意:只有在實現本質為數學的對象時,才會用到許多運算符重載方法。例如,向量或矩陣類可以重載加法運算符,但員工類可能就不用。就較簡單的類而言,可能根本不會用到重載】

【幾乎每個實例的類都會出現一個重載方法是:__init__構造函數。雖然Python不會對實例的屬性進行聲明,但通常也可以通過找到類的__init__方法的代碼,而了解實例有哪些屬性。】

注意:Python中沒有Java中的方法重載,即方法名相同,但參數和參數類型不同,比如__init__函數只能有一個,取最后一個賦給__init__的函數對象。

>>> class Test:
 def __init__():
 pass
 def __init__(self,name,age,sex):
 self.name = name
 self.age = age
 self.sex = sex
>>> a = Test()
Traceback (most recent call last):
 File "<pyshell#54>", line 1, in <module>
 a = Test()
TypeError: __init__() missing 3 required positional arguments: 'name', 'age', and 'sex'

把兩個__init__換了位置之后就沒有報錯了,因為__init__函數已經更改成了沒有參數的:

>>> class Test:
 def __init__(self,name,age,sex):
 self.name = name
 self.age = age
 self.sex = sex
 def __init__(self):
 pass
>>> a = Test()

世界上最簡單的Python類

實際上,我們建立的類可以什么東西都沒有,下列語句建立一個類,其內完全沒有附加的屬性:

>>> class rec:pass

因為沒有寫任何方法,所以我們需要無操作的pass語句。以交互模式執(zhí)行此語句,建立這個類后,就可以完全在最初的class語句外,通過賦值變量名給這個類增加屬性:

>>> rec.name = 'Bob'
>>> rec.age = 40

通過賦值語句創(chuàng)建這些屬性后,就可以用一般的語法將它們取出。這樣用時,類差不多就像C的struct,我們也可以用字典的鍵做類似的事情,但是需要額外的字符。

>>> print(rec.name)
Bob

現在建立兩個該類的實例:

>>> x = rec()
>>> y = rec()
>>> x.name,y.name
('Bob', 'Bob')

這些實例本身沒有屬性,它們只是從類對象那里取出name屬性。不過,如果把一個屬性賦值給一個實例,就會在該對象內創(chuàng)建(或修改)該屬性,而不會因屬性的引用而啟動繼承搜索,因為屬性賦值運算只會影響屬性賦值所在的對象。在這里,x得到自己的name,但y依然繼承附加在他的類上的name:

>>> x.name = 'Gavin'
>>> rec.name,x.name,y.name
('Bob', 'Gavin', 'Bob')

事實上,命名空間對象的屬性通常都是以字典的形式實現的。例如,__dict__屬性是針對大多數基于類的對象的命名空間字典。如下,名稱和__X__內部名稱集合所出現的順序可能隨著版本的不同而有所不同:

>>> rec.__dict__.keys()
dict_keys(['__weakref__', 'name', '__module__', '__doc__', 'age', '__dict__'])
>>> list(x.__dict__.keys())
['name']
>>> list(y.__dict__.keys())
[]

在這里,類的字典顯示出我們進行賦值了的name和age屬性,x有自己的name,而y依然是空的。不過,每個實例都連接至其類以便于繼承,如果你想查看的話,這個連接叫做__class__:

>>> x.__class__
<class '__main__.rec'>

類也有一個__bases__屬性,它是其超類的元祖:

>>> rec.__bases__
(<class 'object'>,)

這兩個屬性時Python在內存中類樹常量的表示方式。

即使是方法也可以完全獨立地在任意類對象的外部創(chuàng)建。例如,下列在任意類之外定義了一個簡單函數,并帶有一個參數:

>>> def upperName(self):
return self.name.upper()

這里與類完全沒有什么關系——這是一個簡單函數,在此時就能予以調用,只要我們傳入一個帶有name屬性的對象:

>>> upperName(x)
'GAVIN'

不過,如果我們把這個簡單函數賦值成類的屬性,就會變成方法,可以由任何實例調用:

>>> rec.method = upperName
>>> x.method()
'GAVIN'
>>> y.method()
'BOB'
>>> rec.method(x)
'GAVIN'

類與字典的關系

看如下字典的示例:

>>> rec = {}
>>> rec['name'] = 'mel'
>>> rec['age'] = 45
>>> rec['job'] = 'trainer/writer'
>>>
>>> print(rec['name'])
mel

這段代碼模擬了像其他語言中記錄這樣的工具,這里也可以用類做同樣的事情:

>>> class rec:pass
>>> rec.name = 'mel'
>>> rec.age = 45
>>> rec.job = 'trainer/writer'
>>>
>>> print(rec.age)
45

這段代碼的語法比其字典等價形式要少很多。它使用了一個空的class語句來產生一個空的命名空間。

這是有效的,但是,對于我們將需要的每一條不同的記錄,都需要一條新的class語句。更通俗的講,我們可以產生一個空類的實例來表示每條不同的記錄:

>>> class rec:pass
>>> pers1 = rec()
>>> pers1.name='mel'
>>> pers1.job = 'trainer'
>>> pers1.age = 40
>>>
>>> pers2 = rec()
>>> pers2.name = 'vls'
>>> pers2.job = 'developer'
>>>
>>> pers1.name,pers2.name
('mel', 'vls')

這里,我們通過對屬性賦值來填充記錄,實際上,同一個類的實例甚至不一定必須有相同的一組屬性名稱,在這個示例中,pers1有唯一的age屬性。每一個實例都有一個不同的屬性字典。

最后,我們可以編寫一個更完整的類來實現記錄及處理:

>>> class Person:
 def __init__(self,name,job):
 self.name = name
 self.job = job
 def info(self):
 return (self.name,self.job)
>>> rec1 = Person('mel','trainer')
>>> rec2 = Person('vls','developer')
>>>
>>> rec1.job,rec2.info()
('trainer', ('vls', 'developer'))

更多關于Python相關內容感興趣的讀者可查看本站專題:《Python面向對象程序設計入門與進階教程》、《Python數據結構與算法教程》、《Python函數使用技巧總結》、《Python字符串操作技巧匯總》、《Python編碼操作技巧總結》及《Python入門與進階經典教程

希望本文所述對大家Python程序設計有所幫助。

相關文章

最新評論