本文實(shí)例講述了Python面向?qū)ο缶幊袒A(chǔ)。分享給大家供大家參考,具體如下:
1、類(lèi)的定義
Python中類(lèi)的定義與對(duì)象的初始化如下,python中所有類(lèi)的父類(lèi)是object,需要繼承。
由于Python是動(dòng)態(tài)語(yǔ)言,因此可以直接為對(duì)象添加屬性并賦值而不必在類(lèi)定義中聲明
1
2
3
4
|
class Person( object ): # 定義一個(gè)Person類(lèi) pass p = Person() # 初始化一個(gè)Person對(duì)象 p.name = "xiaoming" # 對(duì)象屬性賦值 |
Python的類(lèi)初始化方法為_(kāi)_init__(),其第一個(gè)參數(shù)為self代之對(duì)象自身,其后為各個(gè)參數(shù),初始化就是將傳入的參數(shù)賦值給對(duì)象的屬性。**kw代表任意數(shù)量的屬性,通過(guò)key=attribute的形式傳入,之后通過(guò)setattr()方法將每個(gè)屬性賦值給對(duì)象。
直接在class中定義的變量稱(chēng)為類(lèi)屬性,在__init__()中定義的為對(duì)象屬性,類(lèi)屬性供所有對(duì)象共享,對(duì)象只能訪問(wèn)卻無(wú)權(quán)修改。當(dāng)通過(guò)對(duì)象給類(lèi)屬性賦值時(shí),會(huì)為對(duì)象新建一個(gè)同名的對(duì)象屬性,而不是修改類(lèi)屬性。無(wú)論在類(lèi)的內(nèi)部還是外部,都通過(guò)類(lèi)名對(duì)類(lèi)屬性進(jìn)行訪問(wèn)。
以__開(kāi)頭的變量無(wú)法被外部訪問(wèn),類(lèi)似于私有變量。這時(shí)就需要對(duì)象的實(shí)例方法從類(lèi)的內(nèi)部訪問(wèn)私有變量并做出相應(yīng)的操作,這樣在類(lèi)的內(nèi)部定義的方法叫做實(shí)例方法,實(shí)例方法的第一個(gè)參數(shù)默認(rèn)為self代表對(duì)象自己。
相應(yīng)地類(lèi)方法只能訪問(wèn)類(lèi)屬性,其定義方式是在之前添加標(biāo)記@classmethod:,其第一個(gè)參數(shù)cls代表類(lèi)本身
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
class Person( object ): count = 0 # 類(lèi)屬性 @classmethod : def get_count( cls ): # 類(lèi)方法 return cls .count def __init__( self ,name,gender,birth, * * kw): Person.count + = 1 # 訪問(wèn)類(lèi)屬性 self .name = name self .__gender = gender self .birth = birth for k, v in kw.iteritems(): # 遍歷之后的鍵值對(duì),設(shè)置屬性 setattr ( self , k, v) def get_name( self ): # 定義實(shí)例方法 return self .__name xiaoming = Person( 'Xiao Ming' , 'Male' , '1990-1-1' , job = 'Student' ) xiaoming.count = = 9 # 為對(duì)象創(chuàng)建屬性,不會(huì)修改Person.count print (xiaoming.job) # 顯示Student print (xiaoming.__gender) # 無(wú)法訪問(wèn),拋出異常AttributeError print (xiaoming.get_name()) # 通過(guò)實(shí)例方法訪問(wèn)內(nèi)部變量 |
2、類(lèi)的繼承
Python中類(lèi)的繼承方式如下。值得注意的是在子類(lèi)Teacher中需要通過(guò)super(子類(lèi)名,self)調(diào)用父類(lèi)的初始化函數(shù)來(lái)完成對(duì)父類(lèi)中參數(shù)的初始化。也可以直接通過(guò)父類(lèi)名稱(chēng)調(diào)用父類(lèi)的方法
通過(guò)type()方法輸出變量的類(lèi)型,isinstance()可以判斷變量是否是某個(gè)類(lèi)型,dir()方法返回變量的所有屬性和方法列表。輸出對(duì)象t的屬性結(jié)果如下,其中帶__的為默認(rèn)屬性,其余為自定義的屬性
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'course', 'gender', 'name']
1
2
3
4
5
6
7
8
9
10
11
|
class Person( object ): def __init__( self , name, gender): self .name = name self .gender = gender class Teacher(Person): # 繼承父類(lèi)Person def __init__( self , name, gender, course): super (Teacher, self ).__init__(name,gender) # 調(diào)用父類(lèi)的初始化函數(shù) self .course = course # 完成子類(lèi)變量的初始化 t = Teacher( 'Alice' , 'Female' , 'English' ) print ( isinstance (t,Person)) # 結(jié)果為T(mén)rue,子類(lèi)也是父類(lèi)的類(lèi)型 print ( dir (t)) # 顯示對(duì)象的所有屬性 |
和其他面向?qū)ο蟮恼Z(yǔ)言一樣,Python具有多態(tài)的特性,例如父類(lèi)和不同的子類(lèi)都定義了相同的方法,當(dāng)不同的子類(lèi)調(diào)用該方法時(shí)會(huì)調(diào)用自己定義的方法,從而實(shí)現(xiàn)相同的方法具有不同的操作。但python是動(dòng)態(tài)語(yǔ)言,和靜態(tài)語(yǔ)言C++、Java不同的是在調(diào)用實(shí)例方法時(shí),python不檢查類(lèi)型,只要方法存在,參數(shù)正確,就可以調(diào)用。例如原本json的load方法中定義了read()方法用于實(shí)現(xiàn)對(duì)文件的讀取,當(dāng)我們自定義一個(gè)類(lèi)其中包含read()方法時(shí),便可動(dòng)態(tài)調(diào)用實(shí)例方法
1
2
3
4
5
6
|
import json class Students( object ): def read( self ): return r '["Tim", "Bob", "Alice"]' s = Students() print json.load(s) |
一個(gè)子類(lèi)可以同時(shí)繼承兩個(gè)以上的父類(lèi),這個(gè)特性叫做多繼承,當(dāng)有多個(gè)父類(lèi)時(shí),需要在初始化時(shí)指明父類(lèi)
1
2
3
4
5
6
7
8
9
10
11
12
13
|
class A( object ): def __init__( self , a): self .a = a class B( object ): def __init__( self , b): self .b = b class C(A, B): def __init__( self , a, b, c): A.__init__( self , a) B.__init__( self , b) self .c = c c = C( 1 , 2 , 3 ) print (c.a) # 輸出1 |
3、類(lèi)的特殊方法
Python的特殊方法是指定義在類(lèi)中,以__開(kāi)頭和結(jié)尾,由某些函數(shù)或操作符隱式觸發(fā)調(diào)用的方法。例如當(dāng)我們使用print(p)打印一個(gè)Person對(duì)象p時(shí),就會(huì)調(diào)用Person的__str__()方法將p轉(zhuǎn)化為字符串共print輸出,輸出結(jié)果為:<__main__.Person object at 0x000001787CC7C0D0>
當(dāng)我們重新自定義這些特殊方法后,當(dāng)觸發(fā)調(diào)用時(shí)就會(huì)按我們定義的函數(shù)執(zhí)行。例如重新定義__str__(),當(dāng)print()時(shí)就會(huì)顯示My name is Bob
1
2
3
4
5
6
7
8
|
class Person( object ): def __init__( self , name, gender): self .name = name self .gender = gender def __str__( self ): # 重新定義類(lèi)特殊方法 return "My name is " + self .name p = Person( 'Bob' , 'male' ) print (p) # 輸出結(jié)果為:My name is Bob |
__cmp__()方法用于實(shí)現(xiàn)類(lèi)的比較,在排序時(shí)會(huì)自動(dòng)調(diào)用。例如在Student類(lèi)中重新定義該方法,按分?jǐn)?shù)高低對(duì)學(xué)生進(jìn)行排序,其有兩個(gè)參數(shù),第一個(gè)自己self,第二個(gè)是比較的對(duì)象s,如果self應(yīng)該在s之前,則返回-1
1
2
3
4
5
6
7
8
9
10
11
12
13
|
class Student( object ): def __init__( self , name, score): self .name = name self .score = score def __cmp__( self , s): # 重寫(xiě)__cmp__方法 if self .score>s.score: return - 1 # self在s之前 elif self .score<s.score: return 1 else : return 0 L = [Student( 'Tim' , 99 ), Student( 'Bob' , 88 ), Student( 'Alice' , 99 )] Ls = sorted (L) # 使用sorted對(duì)Student類(lèi)進(jìn)行排序 |
__len__()方法用于返回長(zhǎng)度,當(dāng)len()調(diào)用類(lèi)時(shí)會(huì)觸發(fā)
__add__、__sub__、__mul__、__div__分別對(duì)應(yīng)類(lèi)的加減乘除運(yùn)算,當(dāng)類(lèi)遇到運(yùn)算符+-*/時(shí)會(huì)調(diào)用該方法,例如實(shí)現(xiàn)一個(gè)分?jǐn)?shù)類(lèi)Rational的加法:1/2+1/4,通分相加得6/8,最后求最大公約數(shù)后約分得到3/4
__int__、__float__方法在int()、float()調(diào)用類(lèi)時(shí)觸發(fā),可以重新該方法返回一個(gè)int或float結(jié)果
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
def gcd(a, b): # 求最大公約數(shù) if b = = 0 : return a return gcd(b, a % b) class Rational( object ): def __init__( self , p, q): self .p = p self .q = q def __add__( self , r): # 重寫(xiě)加法運(yùn)算 return Rational( self .p * r.q + self .q * r.p, self .q * r.q) def __str__( self ): g = gcd( self .p, self .q) # 將分?jǐn)?shù)約分后輸出 return '%s/%s' % ( self .p / g, self .q / g) def __float__( self ): # 將分?jǐn)?shù)轉(zhuǎn)化為float小數(shù)返回 return float ( self .p) / float ( self .q) r1 = Rational( 1 , 2 ) r2 = Rational( 1 , 4 ) print (r1 + r2) # 兩個(gè)類(lèi)相加 print ( float (r1)) # 輸出小數(shù)形式 |
類(lèi)屬性的裝飾器@property用于將類(lèi)方法轉(zhuǎn)化為屬性,這樣就可以像訪問(wèn)屬性一樣調(diào)用方法。例如Student類(lèi)的__score屬性對(duì)外是不可見(jiàn)的,通過(guò)定義返回方法score使得對(duì)象s可以通過(guò)s.score得到分?jǐn)?shù)值。
@property.setter方法用于對(duì)屬性設(shè)置方法進(jìn)行裝飾,使得可以像給屬性賦值一樣調(diào)用類(lèi)方法。例如當(dāng)使用s.score=99時(shí)會(huì)調(diào)用設(shè)置方法score(self,score),將值傳遞給__score,并且可以對(duì)傳入值的合法性進(jìn)行檢驗(yàn)。
__slots__()用于定義類(lèi)中可以使用的屬性,父類(lèi)定義過(guò)的子類(lèi)中無(wú)需重復(fù)定義。當(dāng)添加新的屬性并賦值時(shí),運(yùn)行會(huì)拋出異常AttributeError
__call__()將一個(gè)類(lèi)實(shí)例變成一個(gè)可調(diào)用對(duì)象,例如一個(gè)Student對(duì)象s,像函數(shù)調(diào)用一樣使用對(duì)象:s('Alice')
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
class Student( object ): __slots__ = ( 'name' , '__score' ) # 本類(lèi)只允許使用name、score兩個(gè)屬性 def __init__( self , name, score): self .name = name self .__score = score @property # 定義屬性返回方法 def score( self ): return self .__score @score .setter # 定義屬性設(shè)置方法 def score( self , score): if score < 0 or score > 100 : raise ValueError( 'invalid score' ) self .__score = score def __call__( self , friend): print ( 'My friend is %s...' % friend) s = Student( 'Bob' , 59 ) s.score = 60 # 調(diào)用屬性設(shè)置方法 print (s.score) # 調(diào)用屬性返回方法 s.grade = 'A' # 拋出異常,無(wú)法添加其他屬性 s( 'Alice' ) # 輸出My friend is Alice... |
__getattribute__(self,attr)、__setattr__(self,attr)、__delattr__(self,attr)分別用于獲取、設(shè)置、刪除屬性時(shí)觸發(fā)的方法,在使用時(shí)應(yīng)注意避免遞歸調(diào)用引起的無(wú)限循環(huán),例如在get方法中再調(diào)用get類(lèi)似的方法導(dǎo)致無(wú)限循環(huán)。
4、模塊管理
為了方便分類(lèi)管理python中的類(lèi)和方法,需要將代碼放在不同的文件中,每個(gè)文件構(gòu)成了一個(gè)獨(dú)立的模塊,不同模塊之間相同的變量名不會(huì)引起命名沖突。但是如果在文件a.py中希望使用文件b.py中的函數(shù)func1,則可以通過(guò)import在a中導(dǎo)入模塊b,并通過(guò)b.func1()調(diào)用該方法。或者通過(guò)from直接引入模塊中的函數(shù)。在引入時(shí)為了防止命名沖突,可以通過(guò)as為引入的函數(shù)起個(gè)別名
1
2
3
4
5
6
7
8
9
|
# 文件a.py中 import b print (b.func1()) # 直接引入函數(shù) from b import func1 print (func1()) # 使用別名 from b import func1 as f1 print (f1()) |
有時(shí)將相同類(lèi)別的模塊放在一個(gè)文件夾內(nèi),就形成了一個(gè)包,python要求一個(gè)包文件夾內(nèi)必須有一個(gè)__init__.py文件才會(huì)識(shí)別為一個(gè)包,即使它是一個(gè)空文件。這時(shí)如果一個(gè)p1包內(nèi)的a.py想訪問(wèn)p2包內(nèi)的b.py中的函數(shù)func2,則操作如下
1
2
3
|
# p1/a.py文件內(nèi) import p2.b print (p2.b.func2()) |
希望本文所述對(duì)大家Python程序設(shè)計(jì)有所幫助。
原文鏈接:https://blog.csdn.net/theVicTory/article/details/103129518