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