【Python】解析Python中类的使用
目錄結(jié)構(gòu):
contents structure [-]
- 類的基本使用
- 專有方法
- 繼承
- 單重繼承
- 多重繼承
- 磚石繼承
1.類的基本使用
下面是類使用的一個(gè)簡(jiǎn)單案例,
class person:"person 類的描述信息"def __init__(self,name="",age=0):self.name = nameself.age = agedef setName(self,name):'''設(shè)置名稱'''self.name = namedef getName(self):'''獲取名稱'''return self.namedef setAge(self,age):self.age = agedef getAge(self):return self.agedef __del__(self):print("person (name:"+self.name+",age:"+str(self.age)+") is deleting")p = person("jame",12); #Output:jame print(p.getName()) #效果和下面的調(diào)用方式是一樣的 #person.getName(p)#Output:12 print(p.getAge()) #效果和下面的調(diào)用方式是一樣的 #person.getAge(self)#Output: person 類的描述信息 print(p.__doc__)#輸出person類的幫助信息 print(help(person))del p
輸出:
jame
12
person (name:jame,age:12) is deleting
person 類的描述信息
Help on class person in module __main__:class person(builtins.object)| person 類的描述信息| | Methods defined here:|
...
__init__函數(shù)是構(gòu)造函數(shù),在構(gòu)造對(duì)象的時(shí)候會(huì)自動(dòng)調(diào)用該函數(shù)。
__del__函數(shù)是析構(gòu)函數(shù),在使用del刪除目標(biāo)對(duì)象時(shí)會(huì)自動(dòng)調(diào)用該方法。
Python中,類不可以定義多個(gè)構(gòu)造方法,只能定義一個(gè)構(gòu)造方法。所有成員實(shí)例函數(shù)的第一個(gè)參數(shù)都必須是self參數(shù)(也可以有非self參數(shù)的成員函數(shù),下面會(huì)講解)。python會(huì)自動(dòng)創(chuàng)建成員屬性,無需提前定義,例如self.name=name。
?
類屬性
類屬性的定義無需使用self參數(shù),可以直接定義到類中。類屬性可以直接通過類名調(diào)用。
class Person:type = "哺乳類"def __init__(self,name,age):self.name = nameself.age = agep = Person("luyis",13) #通過類名調(diào)用類屬性 print(Person.type) #通過對(duì)象調(diào)用類屬性 print(p.type)
?
靜態(tài)方法
靜態(tài)方法是類中的函數(shù),不需要實(shí)例。靜態(tài)方法主要是用來存放邏輯性的代碼,主要是一些邏輯屬于類,但是和類本身沒有交互,即在靜態(tài)方法中,不會(huì)涉及到類中的方法和屬性的操作。用 @staticmethod 裝飾的不帶 self 參數(shù)的方法,類的靜態(tài)方法可以沒有參數(shù),可以直接使用類名調(diào)用。
import time class TimeTest:def __init__(self):pass#靜態(tài)方法 @staticmethoddef show_time():print(time.strftime("%H:%M:%S", time.localtime()))TimeTest.show_time()
?
?
類方法
類方法是將類本身作為對(duì)象進(jìn)行操作的方法。默認(rèn)有個(gè) cls 參數(shù),可以被類和對(duì)象調(diào)用,需要加上 @classmethod 裝飾器。
class ClassTest:num = 0def __init__(self,num):ClassTest.num = num#類方法 @classmethoddef showNum(cls):print(cls.num)c = ClassTest(20) #通過類直接調(diào)用 ClassTest.showNum() #通過實(shí)例對(duì)象調(diào)用 c.showNum()
?
?
私有成員
Python中的私有成員,不能在類外面直接訪問。私有成員只需要在成員前面加上兩條下劃線(__)就表明該成員是私有的了。
class Person:#__type是私有成員__type = "哺乳類"def __init__(self,name="",age=0,country="中國(guó)"):#__name,__age是私有成員self.__name = nameself.__age = ageself.__setcountry(country)def get_name(self):return self.__namedef get_age(self):return self.__agedef set_name(self,name):self.__name = namedef set_age(self,age):self.__age = age#__setcountry是私有函數(shù)def __setcountry(self,cty):self.country = cty@classmethoddef get_type(cls):return cls.__type@classmethoddef set_type(cls,type):cls.__type = typep = Person("jame",21) print(p.get_name()) print(p.get_age()) print("--------------------")p.set_name("charlse") p.set_age(31) print(p.get_name()) print(p.get_age()) print("-------------------")print(Person.get_type()) print("------------------")Person.set_type("靈長(zhǎng)類") print(Person.get_type())
輸出:
jame
21
--------------------
charlse
31
-------------------
哺乳類
------------------
靈長(zhǎng)類
定義私有成員的格式:
__xxx:私有成員,只有類對(duì)象自己能訪問,子類對(duì)象不能直接訪問到這個(gè)成員,
注意:雖然不能在類外直接訪問到類的私有成員,但在對(duì)象外部可以通過“ 對(duì)象名._類名__xxx ”這樣的特殊方式來訪問類的私有成員。應(yīng)此,在Python中不存在嚴(yán)格意義上的私有成員。
class Person:#__type是私有成員__type = "哺乳類"def __init__(self,name="",age=0):#__name,__age是私有成員self.__name = nameself.__age = agep = Person("Emma",32); #直接訪問私有成員的值 print(p._Person__type) print(p._Person__name) print(p._Person__age)#直接修改私有成員的值 p._Person__age = 33 p._Person__name = "Angela" p._Person__type = "靈長(zhǎng)類"print("-------------------") print(p._Person__type) print(p._Person__name) print(p._Person__age)
輸出:
哺乳類
Emma
32
-------------------
靈長(zhǎng)類
Angela
33 ?
?
2.專有方法
Python除了自定義私有變量和方法外,還可以定義專有方法。專有方法是在特殊情況下或使用特殊語法時(shí)由python調(diào)用的,而不是像普通方法一樣在代碼中直接調(diào)用。看到形如__XXX__的變量或函數(shù)名時(shí)就需要注意下,這在python中是有特殊用途的,下面是Python中的部分專用方法:
__init__ : 構(gòu)造函數(shù),在生成對(duì)象時(shí)調(diào)用
__del__ : 析構(gòu)函數(shù),釋放對(duì)象時(shí)使用
__str__: 打印,轉(zhuǎn)換,適合于展示給用戶看的
__repr__ : 打印,轉(zhuǎn)換,適合開發(fā)者調(diào)試
__setitem__ : 按照索引賦值
__getitem__: 按照索引獲取值
__len__: 獲得長(zhǎng)度
__call__: 函數(shù)調(diào)用
__add__: 加運(yùn)算
__sub__: 減運(yùn)算
__mul__: 乘運(yùn)算
__div__: 除運(yùn)算
__mod__: 求余運(yùn)算
__pow__: 乘方
__doc__: 說明文檔信息
上面筆者已經(jīng)講解過__init__和__del__函數(shù)的使用了,應(yīng)此筆者不再這里重復(fù)綴述了。筆者接下來講解其它的專有方法的用法:
?
__str__,__repr__
都是用于將對(duì)象轉(zhuǎn)化為字符串的內(nèi)置方法。
但是 repr() 函數(shù)將對(duì)象轉(zhuǎn)化為供解釋器讀取的形式,__str__只是覆蓋了__repr__以得到更友好的用戶顯示。
例如:
>>> y = 'a string' >>> repr(y) "'a string'" >>> str(y) 'a string'
repr函數(shù)的返回字符串可以再次傳遞給eval函數(shù)。但是str函數(shù)的返回值傳遞給eval顯然是不合適。
>>> y == eval(repr(y)) True >>> y == eval(str(y)) Traceback (most recent call last):File "<stdin>", line 1, in <module>File "<string>", line 1a string^ SyntaxError: unexpected EOF while parsing
?
repr返回的字符串應(yīng)該是編譯器能夠再次解析的,str返回的字符串應(yīng)該可以是易閱讀的
在知道了repr和str的區(qū)別后,我們就知道該如何自定義__repr__和__str__函數(shù)了。
class person:def __init__(self,name="",age=0):self.__name = nameself.__age = agedef __str__(self):return "name:%s,age:%d"%(self.__name,self.__age)def __repr__(self):return "person(name='%s',age=%d)"%(self.__name,self.__age)p = person("jame",12) #Output: name:jame,age=12 print(str(p))#same as print(p)#Output: person(name='jame',age=12) print(repr(p))p2 = eval(repr(p)) #Output: name:jame,age=12 print(p2)
?
?
__setitem__,__getitem__
用于通過下標(biāo)來設(shè)置和獲取值,可以直接使用[]符來操作。
class DicDecorate:def __init__(self,dic):self.__dic = dicdef __getitem__(self,key):return self.__dic[key]def __setitem__(self,key,val):self.__dic[key] = valdicdec = DicDecorate({})dicdec[0] = "hello" dicdec[1] = "word"print(dicdec[0]) print(dicdec[1])
__len__():
當(dāng)調(diào)用len函數(shù)時(shí)會(huì)調(diào)用該方法。
lass DicDecorate:def __init__(self,dic):self.__dic = dicdef __len__(self):return len(self.__dic);dicdec = DicDecorate({}) print(len(dicdec))
?
__call__()
關(guān)于 __call__ 方法,不得不先提到一個(gè)概念,就是可調(diào)用對(duì)象(callable),我們平時(shí)自定義的函數(shù)、內(nèi)置函數(shù)和類都屬于可調(diào)用對(duì)象,但凡是可以把一對(duì)括號(hào)()應(yīng)用到某個(gè)對(duì)象身上都可稱之為可調(diào)用對(duì)象,判斷對(duì)象是否為可調(diào)用對(duì)象可以用函數(shù) callable。
如果在類中實(shí)現(xiàn)了 __call__ 方法,那么實(shí)例對(duì)象也將成為一個(gè)可調(diào)用對(duì)象。
class Entity:def __init__(self, x, y):self.x, self.y = x, ydef __call__(self, x, y):self.x, self.y = x, ydef __str__(self):return "x=%s,y=%s"%(self.x,self.y)e = Entity(2, 3) # 創(chuàng)建實(shí)例 if(callable(e)):e(4, 5) #實(shí)例可以象函數(shù)那樣執(zhí)行,并傳入x y值,修改對(duì)象的x y #Output:x=4,y=5 print(e)
?
__add__: 加運(yùn)算 __sub__: 減運(yùn)算 __mul__: 乘運(yùn)算 __div__: 除運(yùn)算 __mod__: 求余運(yùn)算 __pow__: 冪運(yùn)算
class Vector:def __init__(self, a, b):self.a = aself.b = bdef __str__(self):return 'Vector (%d, %d)' % (self.a, self.b)def __add__(self,other):return Vector(self.a + other.a, self.b + other.b)v1 = Vector(2,10) v2 = Vector(5,-2) print (v1 + v2)
?
?
3. 繼承
3.1 單重繼承
Python繼承的語法格式:
class ClassName1(ClassName2):statement
其中
ClassName1:派生類
ClassName2:基類
class Shape:def __init__(self,type,area):self.type = typeself.area = areadef describe(self):return "Share type:%s,area=%f"%(self.type,self.area) class Square(Shape):def __init__(self,area):super().__init__("square",area); square = Square(12.1) print(square.describe())
和其它編程語言一樣,可以重寫父類中的方法,可以繼承父類中開放的屬性和方法(不能繼承父類中的私有屬性和方法)。
?
3.2 多重繼承
除了單重繼承,Python還支持多重繼承
class ClassName1(ClassName2,ClassName3,ClassName4...):statement
Python多重繼承中順序繼承是一個(gè)非常重要的概念,如果繼承的多個(gè)父類中有相同的方法名,但在派生類中使用時(shí)未指定父類名,則Python解釋器將從左至右搜索,即調(diào)用先繼承的類中的同名方法。
class A:def test(self):print("I am in Class A"); class B:def test(self):print("I am in Class B");class C(A,B):def __call__(self):#調(diào)用A類中的test方法 self.test()#可以通過類名顯示指定調(diào)用B類中的test方法 B.test(self)class D(B,A):def __call__(self):#調(diào)用B類的test方法 self.test()#通過類名顯示指定要調(diào)用A類中的test方法 A.test(self)c = C() c() print("---------------"); d = D() d()
輸出:
I am in Class A
I am in Class B
-----------------
I am in Class B
I am in Class A 通過上面的結(jié)果可以看出,子類在父類中查找方法的順序是從左到右的。
?
3.3 磚石繼承
磚石繼承問題是Python多重繼承中的典型問題,下面先通過一張圖片看看什么是磚石繼承。
通過這張圖片看出,D繼承了B和C,B和C又派生于A,在調(diào)用D類的test()方法時(shí),會(huì)再去調(diào)用B和C的test()方法,B和C又會(huì)去調(diào)用A的test()方法,所以A類的test()方法在理論應(yīng)該會(huì)被調(diào)用兩次,例如:
class A:def test(self):print("I am in Class A"); class B(A):def test(self):A.test(self);print("I am in Class B") class C(A):def test(self):A.test(self);print("I am in Class C");class D(B,C):def test(self):B.test(self)C.test(self)print("I am in Class D")d = D() d.test()
輸出:
I am in Class A
I am in Class B
I am in Class A
I am in Class C
I am in Class D
從上面的輸出結(jié)果可以看出,A類的test()被調(diào)用了兩次。在有些情況這種邏輯將會(huì)造成極大的Bug,比如一筆銀行轉(zhuǎn)賬記錄轉(zhuǎn)了兩次。要避免這種情況,可以使用super()方法,當(dāng)使用super()調(diào)用父類的test方法時(shí),會(huì)轉(zhuǎn)而去調(diào)用下一個(gè)重寫了該super類的test方法,若沒有的話才會(huì)去調(diào)用父類的test方法。
案例:
class A:def test(self):print("I am in Class A") class B(A):def test(self):super().test() #不能替換為A.test(self)print("I am in Class B") class C(A):def test(self):super().test()print("I am in Class C")class D(B,C):def test(self):super().test() #可以替換為B.test(self)print("I am in Class D")d = D() d.test()
輸出:
I am in Class A
I am in Class C
I am in Class B
I am in Class D
通過上面的結(jié)果我們可以看出,super.test()和父類.test(self)是不一樣的,在B類中使用super()調(diào)用父類的test()時(shí),會(huì)去尋找B實(shí)例后的下一個(gè)類是否重寫A類的test()方法,由于類D繼承了類B和類C,所以類C在類B后,而且類C又重寫了test()方法,應(yīng)此會(huì)直接調(diào)用類C的test()方法。在類C的test()方法中,又使用了super().test()調(diào)用父類的test(),所以又會(huì)去尋找C實(shí)例后的下一個(gè)類有重寫A類的test方法,因?yàn)轭怐只繼承了B和C,并且類C是最后一個(gè),所以C后沒有實(shí)例直接重寫A類的test()方法,因此直接去調(diào)用A類的test()方法。最終完整的方法壓棧順序是D->B->C->A。
下面的邏輯和上面案例中使用super()的邏輯是等同的:
class A:def test(self):print("I am in Class A") class B(A):def test(self):C.test(self)#調(diào)用C class C(A):def test(self):A.test(self)#調(diào)用A class D(B,C):def test(self):B.test(self)#調(diào)用B
上面的邏輯變成了如圖所示:
轉(zhuǎn)載于:https://www.cnblogs.com/HDK2016/p/10964792.html
總結(jié)
以上是生活随笔為你收集整理的【Python】解析Python中类的使用的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 找原头,最好是高清的
- 下一篇: 偏前端 - vue-cli(axios请