Python面向?qū)ο缶幊袒A(chǔ)實(shí)例分析
本文實(shí)例講述了Python面向?qū)ο缶幊袒A(chǔ)。分享給大家供大家參考,具體如下:
1、類的定義
Python中類的定義與對象的初始化如下,python中所有類的父類是object,需要繼承。
由于Python是動(dòng)態(tài)語言,因此可以直接為對象添加屬性并賦值而不必在類定義中聲明
class Person(object): # 定義一個(gè)Person類 pass p = Person() # 初始化一個(gè)Person對象 p.name="xiaoming" # 對象屬性賦值
Python的類初始化方法為__init__(),其第一個(gè)參數(shù)為self代之對象自身,其后為各個(gè)參數(shù),初始化就是將傳入的參數(shù)賦值給對象的屬性。**kw代表任意數(shù)量的屬性,通過key=attribute的形式傳入,之后通過setattr()方法將每個(gè)屬性賦值給對象。
直接在class中定義的變量稱為類屬性,在__init__()中定義的為對象屬性,類屬性供所有對象共享,對象只能訪問卻無權(quán)修改。當(dāng)通過對象給類屬性賦值時(shí),會(huì)為對象新建一個(gè)同名的對象屬性,而不是修改類屬性。無論在類的內(nèi)部還是外部,都通過類名對類屬性進(jìn)行訪問。
以__開頭的變量無法被外部訪問,類似于私有變量。這時(shí)就需要對象的實(shí)例方法從類的內(nèi)部訪問私有變量并做出相應(yīng)的操作,這樣在類的內(nèi)部定義的方法叫做實(shí)例方法,實(shí)例方法的第一個(gè)參數(shù)默認(rèn)為self代表對象自己。
相應(yīng)地類方法只能訪問類屬性,其定義方式是在之前添加標(biāo)記@classmethod:,其第一個(gè)參數(shù)cls代表類本身
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(): # 遍歷之后的鍵值對,設(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 # 為對象創(chuàng)建屬性,不會(huì)修改Person.count
print(xiaoming.job) # 顯示Student
print(xiaoming.__gender) # 無法訪問,拋出異常AttributeError
print(xiaoming.get_name()) # 通過實(shí)例方法訪問內(nèi)部變量
2、類的繼承
Python中類的繼承方式如下。值得注意的是在子類Teacher中需要通過super(子類名,self)調(diào)用父類的初始化函數(shù)來完成對父類中參數(shù)的初始化。也可以直接通過父類名稱調(diào)用父類的方法
通過type()方法輸出變量的類型,isinstance()可以判斷變量是否是某個(gè)類型,dir()方法返回變量的所有屬性和方法列表。輸出對象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']
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) # 調(diào)用父類的初始化函數(shù)
self.course= course # 完成子類變量的初始化
t = Teacher('Alice', 'Female', 'English')
print(isinstance(t,Person)) # 結(jié)果為True,子類也是父類的類型
print(dir(t)) # 顯示對象的所有屬性
和其他面向?qū)ο蟮恼Z言一樣,Python具有多態(tài)的特性,例如父類和不同的子類都定義了相同的方法,當(dāng)不同的子類調(diào)用該方法時(shí)會(huì)調(diào)用自己定義的方法,從而實(shí)現(xiàn)相同的方法具有不同的操作。但python是動(dòng)態(tài)語言,和靜態(tài)語言C++、Java不同的是在調(diào)用實(shí)例方法時(shí),python不檢查類型,只要方法存在,參數(shù)正確,就可以調(diào)用。例如原本json的load方法中定義了read()方法用于實(shí)現(xiàn)對文件的讀取,當(dāng)我們自定義一個(gè)類其中包含read()方法時(shí),便可動(dòng)態(tài)調(diào)用實(shí)例方法
import json
class Students(object):
def read(self):
return r'["Tim", "Bob", "Alice"]'
s = Students()
print json.load(s)
一個(gè)子類可以同時(shí)繼承兩個(gè)以上的父類,這個(gè)特性叫做多繼承,當(dāng)有多個(gè)父類時(shí),需要在初始化時(shí)指明父類
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的特殊方法是指定義在類中,以__開頭和結(jié)尾,由某些函數(shù)或操作符隱式觸發(fā)調(diào)用的方法。例如當(dāng)我們使用print(p)打印一個(gè)Person對象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
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) # 輸出結(jié)果為:My name is Bob
__cmp__()方法用于實(shí)現(xiàn)類的比較,在排序時(shí)會(huì)自動(dòng)調(diào)用。例如在Student類中重新定義該方法,按分?jǐn)?shù)高低對學(xué)生進(jìn)行排序,其有兩個(gè)參數(shù),第一個(gè)自己self,第二個(gè)是比較的對象s,如果self應(yīng)該在s之前,則返回-1
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類進(jìn)行排序
__len__()方法用于返回長度,當(dāng)len()調(diào)用類時(shí)會(huì)觸發(fā)
__add__、__sub__、__mul__、__div__分別對應(yīng)類的加減乘除運(yùn)算,當(dāng)類遇到運(yùn)算符+-*/時(shí)會(huì)調(diào)用該方法,例如實(shí)現(xiàn)一個(gè)分?jǐn)?shù)類Rational的加法:1/2+1/4,通分相加得6/8,最后求最大公約數(shù)后約分得到3/4
__int__、__float__方法在int()、float()調(diào)用類時(shí)觸發(fā),可以重新該方法返回一個(gè)int或float結(jié)果
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): # 重寫加法運(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è)類相加
print(float(r1)) # 輸出小數(shù)形式
類屬性的裝飾器@property用于將類方法轉(zhuǎn)化為屬性,這樣就可以像訪問屬性一樣調(diào)用方法。例如Student類的__score屬性對外是不可見的,通過定義返回方法score使得對象s可以通過s.score得到分?jǐn)?shù)值。
@property.setter方法用于對屬性設(shè)置方法進(jìn)行裝飾,使得可以像給屬性賦值一樣調(diào)用類方法。例如當(dāng)使用s.score=99時(shí)會(huì)調(diào)用設(shè)置方法score(self,score),將值傳遞給__score,并且可以對傳入值的合法性進(jìn)行檢驗(yàn)。
__slots__()用于定義類中可以使用的屬性,父類定義過的子類中無需重復(fù)定義。當(dāng)添加新的屬性并賦值時(shí),運(yùn)行會(huì)拋出異常AttributeError
__call__()將一個(gè)類實(shí)例變成一個(gè)可調(diào)用對象,例如一個(gè)Student對象s,像函數(shù)調(diào)用一樣使用對象:s('Alice')
class Student(object):
__slots__ = ('name','__score') # 本類只允許使用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' # 拋出異常,無法添加其他屬性
s('Alice') # 輸出My friend is Alice...
__getattribute__(self,attr)、__setattr__(self,attr)、__delattr__(self,attr)分別用于獲取、設(shè)置、刪除屬性時(shí)觸發(fā)的方法,在使用時(shí)應(yīng)注意避免遞歸調(diào)用引起的無限循環(huán),例如在get方法中再調(diào)用get類似的方法導(dǎo)致無限循環(huán)。
4、模塊管理
為了方便分類管理python中的類和方法,需要將代碼放在不同的文件中,每個(gè)文件構(gòu)成了一個(gè)獨(dú)立的模塊,不同模塊之間相同的變量名不會(huì)引起命名沖突。但是如果在文件a.py中希望使用文件b.py中的函數(shù)func1,則可以通過import在a中導(dǎo)入模塊b,并通過b.func1()調(diào)用該方法?;蛘咄ㄟ^from直接引入模塊中的函數(shù)。在引入時(shí)為了防止命名沖突,可以通過as為引入的函數(shù)起個(gè)別名
# 文件a.py中 import b print(b.func1()) # 直接引入函數(shù) from b import func1 print(func1()) # 使用別名 from b import func1 as f1 print(f1())
有時(shí)將相同類別的模塊放在一個(gè)文件夾內(nèi),就形成了一個(gè)包,python要求一個(gè)包文件夾內(nèi)必須有一個(gè)__init__.py文件才會(huì)識(shí)別為一個(gè)包,即使它是一個(gè)空文件。這時(shí)如果一個(gè)p1包內(nèi)的a.py想訪問p2包內(nèi)的b.py中的函數(shù)func2,則操作如下
# p1/a.py文件內(nèi) import p2.b print (p2.b.func2())
更多關(guān)于Python相關(guān)內(nèi)容感興趣的讀者可查看本站專題:《Python面向?qū)ο蟪绦蛟O(shè)計(jì)入門與進(jìn)階教程》、《Python數(shù)據(jù)結(jié)構(gòu)與算法教程》、《Python函數(shù)使用技巧總結(jié)》、《Python字符串操作技巧匯總》、《Python編碼操作技巧總結(jié)》及《Python入門與進(jìn)階經(jīng)典教程》
希望本文所述對大家Python程序設(shè)計(jì)有所幫助。
相關(guān)文章
利用python將xml文件解析成html文件的實(shí)現(xiàn)方法
下面小編就為大家分享一篇利用python將xml文件解析成html文件的實(shí)現(xiàn)方法,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2017-12-12
Python輕量級ORM框架Peewee訪問sqlite數(shù)據(jù)庫的方法詳解
這篇文章主要介紹了Python輕量級ORM框架Peewee訪問sqlite數(shù)據(jù)庫的方法,結(jié)合實(shí)例形式較為詳細(xì)的分析了ORM框架的概念、功能及peewee的安裝、使用及操作sqlite數(shù)據(jù)庫的方法,需要的朋友可以參考下2017-07-07
如何使用Tkinter進(jìn)行窗口的管理與設(shè)置
Tkinter是Python的標(biāo)準(zhǔn)GUI庫,它實(shí)際是建立在Tk技術(shù)上的。在大多數(shù)Unix平臺(tái)以及Windows系統(tǒng)上都可用2021-06-06
python實(shí)現(xiàn)網(wǎng)頁鏈接提取的方法分享
這篇文章主要介紹了python實(shí)現(xiàn)的網(wǎng)頁鏈接提取的方法,需要的朋友可以參考下2014-02-02

