您好,登錄后才能下訂單哦!
1 面向過程編程
以指令為核心:圍繞“正在發(fā)生什么”進(jìn)行編寫
面向過程:程序= 算法+ 數(shù)據(jù)結(jié)構(gòu)
面向過程編程:程序具有一系列線性步驟,主體思想是代碼作用于數(shù)據(jù),以指令為核心,核心是設(shè)計(jì)算法,
2 面向函數(shù)的編程
3 面向?qū)ο蟮木幊?/p>
面向?qū)ο缶幊?-object oriented programming ,簡(jiǎn)稱OOP,把對(duì)象作為程序的基本單元,一個(gè)對(duì)象包含了數(shù)據(jù)和操作數(shù)據(jù)的函數(shù)
面向過程把函數(shù)繼續(xù)切分稱為子函數(shù),來降低系統(tǒng)的復(fù)雜度。
面向?qū)ο缶幊蹋∣OP)
程序 = 指令 + 數(shù)據(jù)/算法 + 數(shù)據(jù)結(jié)構(gòu)
以數(shù)據(jù)為核心: 圍繞“將影響誰(shuí)”進(jìn)行編寫
面向?qū)ο缶幊蹋∣OP):圍繞數(shù)據(jù)以及為數(shù)據(jù)嚴(yán)格定義的接口來組織程序,用數(shù)據(jù)控制對(duì)代碼的訪問,面向數(shù)據(jù),以及能夠?qū)@些數(shù)據(jù)采取的操作進(jìn)行,代碼執(zhí)行過成,不能跳過數(shù)據(jù)
面向?qū)ο缶幊痰暮诵母拍睿?br/>所有編程語(yǔ)言的最終目的都是提供一種抽象方法
在機(jī)器模型(“解空間”或“方案空間”)與實(shí)際解決問題的問題模型(“問題空間”)之間,程序員必須建立一種聯(lián)系
將問題空間中的元素以及他們?cè)诮饪臻g中的標(biāo)識(shí)物抽象為對(duì)象,并允許通過問題來描述問題而不是通過方案來描述問題
可以把實(shí)例(某個(gè)類的實(shí)例)想象成一種新型變量,他保存這數(shù)據(jù),但可以對(duì)自身數(shù)據(jù)執(zhí)行操作,實(shí)例可以對(duì)自身數(shù)據(jù)做操作
定義了被多個(gè)同一類型對(duì)象共享的結(jié)構(gòu)和行為(數(shù)據(jù)和代碼)
類是抽象的,實(shí)例是具體的,類是(概念,抽象的概念模型),類本身是不能被操作的,須有實(shí)例化的對(duì)象才能操作
類內(nèi)部有兩個(gè)核心成員:代碼和數(shù)據(jù),都叫類成員
數(shù)據(jù):成員變量或?qū)嵗兞?br/>成員方法: 簡(jiǎn)稱為方法,是操作數(shù)據(jù)的代碼,用于定義如何使用成員變量,因此一個(gè)類的行為和接口是通過方法來定義的
類:將同一種具體的物事的共同特性抽想出來的表現(xiàn)
實(shí)例是類的具體表現(xiàn)形式,類存在的目的就是為了實(shí)例化。類是抽象的,實(shí)例是具體的
calss 類名(父類):
類的內(nèi)容
類后面有括號(hào)的稱為新式類,沒有括號(hào)稱為經(jīng)典類。
括號(hào)里面的內(nèi)容是父類的名稱,程序中,所有父類都是object
類的查看:
當(dāng)類的實(shí)例化后,類的屬性是不變的
類的數(shù)據(jù)屬性是可變的,當(dāng)在實(shí)例處修改類的數(shù)據(jù)屬性時(shí),其類本身的數(shù)據(jù)屬性不變。
當(dāng)類的數(shù)據(jù)屬性發(fā)生改變時(shí),原本已經(jīng)改變的實(shí)例的數(shù)據(jù)屬性不會(huì)再次改變,而新創(chuàng)建的實(shí)例的數(shù)據(jù)屬性會(huì)發(fā)生改變
#!/usr/local/bin/python3.6
#coding:utf-8
class MyClass:
'''is example class'''
x='abc' # 類的屬性
def foo(self): # 類的屬性,也是方法
return (self,'MyClass')
myclass=MyClass() # 進(jìn)行實(shí)例化操作
print (myclass.x) #調(diào)用類的屬性
print (MyClass.x) # 類調(diào)用類屬性
print (MyClass.foo(1)) # 類調(diào)用類方法
print (myclass.foo()) # 調(diào)用類的方法
print (type(myclass)) # 打印類型
print (id(MyClass)) # 打印類的實(shí)例地址
print (id(myclass)) # 打印類的內(nèi)存地址
結(jié)果如下
其實(shí)例化都的內(nèi)存地址和類本身的內(nèi)存地址不同,且實(shí)例可以調(diào)用類的屬性和方法,類自身也可以進(jìn)行相關(guān)的調(diào)用處理
在類中定義的函數(shù)教方法,類的方法中,要求第一個(gè)形參必須是self,而self實(shí)際上是類實(shí)例化后的對(duì)象本身
實(shí)例化后獲得的實(shí)例,是不同的實(shí)例,即使使用相同的參數(shù)實(shí)例化,也得到不一樣的對(duì)象,其會(huì)先調(diào)用new 進(jìn)行實(shí)例化,然后調(diào)用_init_ 進(jìn)行初始化
實(shí)例化后,會(huì)自動(dòng)調(diào)用__init__方法,這個(gè)方法的第一個(gè)參數(shù)必須留給self,其他參數(shù)隨意
類方法的定義
類方法的調(diào)用
#!/usr/local/bin/python3.6
#coding:utf-8
class MyClass:
'''is example class'''
x='abc' # 類的屬性
y='cbd'
def __init__(self): # 初始化時(shí)進(jìn)行打印,并顯示結(jié)果,其__init__方法中不能return,其只能用做初始化
print ('init')
def foo(self):
return (self.x)
def foo1(self):
return (self.y)
myclass=MyClass() # 對(duì)象實(shí)例化
print (myclass.foo())
print (myclass.foo1())
結(jié)果如下
#!/usr/local/bin/python3.6
#coding:utf-8
class Person:
def __init__(self,name,age=20):
self.name=name # 此處的name始終和上述的self后面的name相對(duì)應(yīng),下面相同
self.x=age
def showage(self):
print ('{} is {}'.format(self.name,self.x)) # 此處self.x 始終和上面的相同,其中age相當(dāng)于形參
tom=Person('tom') #對(duì)參數(shù)進(jìn)行實(shí)例化操作
jerry=Person('jerry',10) # 對(duì)參數(shù)進(jìn)行實(shí)例化
tom.showage() #打印其方法
jerry.showage()
a=Person('a') # 其獲取到的參數(shù)完全相同
b=Person('a')
print (a is b) # 其內(nèi)存地址不同
print (a==b) # 其獲取結(jié)果不同,
結(jié)果如下
#!/usr/local/bin/python3.6
#coding:utf-8
class Person:
x='abc'
def __init__(self,name,age=18):
self.name=name
self.age=age
def show(self,x,y): # 通過此處的參數(shù),可修改類中的屬性
self.name=x # 修改name的屬性
self.age=y
Person.x=x # 修改類屬性
print (self.name,self.age,x)
tom=Person('tom')
tom.show('jerry',20)
print (Person.x) # 其返回結(jié)果為修改類屬性后的結(jié)果
結(jié)果如下
1 class._name_ 類的名稱顯示
2 class._doc_ 類的幫助文檔
3 class._base_ 類的父類/基類
4 class._module_ 類的模塊,當(dāng)不是導(dǎo)入的模塊的類時(shí),其執(zhí)行結(jié)果為main,當(dāng)為模塊導(dǎo)入時(shí),其執(zhí)行結(jié)果為模塊名
5 class._dict_ 對(duì)象屬性的字典,用于遍歷和查找屬性,每個(gè)對(duì)象中保存這自己的屬性,類的屬性在類字典中,實(shí)例的屬性在實(shí)例的字典中
6 class._class_ 對(duì)象的類型,__class__和type中的類型是相同的,在python3中相同,在早期的python2 中有某些事不相同的
7 class._qualname_ 類的限定名
#!/usr/local/bin/python3.6
#coding:utf-8
class Person:
x='abc'
def __init__(self,name,age=18):
self.name=name
self.age=age
def show(self,x,y): # 通過此處的參數(shù),可修改類中的屬性
self.name=x # 修改name的屬性
self.age=y
Person.x=x # 修改類屬性
print (self.name,self.age,x)
tom=Person('tom')
print (tom.__class__,Person.__class__) # 打印實(shí)例類型和類的類型
print (tom.__dict__,Person.__dict__) # 打印實(shí)例的屬性字典和類的屬性字典
print (tom.__qualname__,Person.__qualname__) # 打印實(shí)例的限定名和類的限定名,默認(rèn)的,只有類有限定名
結(jié)果如下
如需輸出,則需要
#!/usr/local/bin/python3.6
#coding:utf-8
class Person:
x='abc'
def __init__(self,name,age=18):
self.name=name
self.age=age
def show(self,x,y): # 通過此處的參數(shù),可修改類中的屬性
self.name=x # 修改name的屬性
self.age=y
Person.x=x # 修改類屬性
print (self.name,self.age,x)
tom=Person('tom')
print (tom.__class__.__qualname__) #此處通過__class__吊起該實(shí)例的類,通過類調(diào)用其限定名即可
print (isinstance(tom,Person)) #通過此處判斷該類是否是該實(shí)例的類
print(isinstance(tom,tom.__class__))
結(jié)果
#!/usr/local/bin/python3.6
#coding:utf-8
class Person:
x='abc'
def __init__(self,name,age=18):
self.name=name
self.age=age
def show(self,x,y): # 通過此處的參數(shù),可修改類中的屬性
self.name=x # 修改name的屬性
self.age=y
Person.x=x # 修改類屬性
print (self.name,self.age,x)
tom=Person('tom')
jerry=Person('jerry',20)
print (tom.__dict__,jerry.__dict__,Person.__dict__,sep='\n')# 打印實(shí)例和類的屬性字典
結(jié)果如下
#!/usr/local/bin/python3.6
#coding:utf-8
class Person:
x='abc'
age=3
height=170
def __init__(self,name,age=18):
self.name=name
self.age=age
tom=Person('tom')
jerry=Person('jerry',20)
Person.age=30
print (Person.__dict__,tom.__dict__,jerry.__dict__,sep='\n') #此處打印類和實(shí)例對(duì)象屬性字典
print (Person.age,tom.age,jerry.age) # 結(jié)果為30,18,20
Person.height+=30
print (Person.__dict__,tom.__dict__,jerry.__dict__,sep='\n')
print (Person.height,tom.height,jerry.height) # 結(jié)果為200,200,200
tom.height=180 # 當(dāng)此處給單獨(dú)的對(duì)象添加了類的屬性并賦值后,其對(duì)象tom的屬性字典中的值也會(huì)隨之變化
print (Person.__dict__,tom.__dict__,jerry.__dict__,sep='\n') # 此處tom的字典屬性中也增加了height的key,且其值為180
print (Person.height,tom.height,jerry.height) #結(jié)果為200,180,200
jerry.height+=30 # 此處添加了實(shí)例的屬性后,其對(duì)象字典中的對(duì)象屬性也會(huì)隨之增加
print (Person.__dict__,tom.__dict__,jerry.__dict__,sep='\n') # 此處jerry 的字典屬性中也增加了height的key,且其值為230
print (Person.height,tom.height,jerry.height) # 結(jié)果為200,180,230
結(jié)果如下
#!/usr/local/bin/python3.6
#coding:utf-8
class Person:
x='abc'
age=3
height=170
def __init__(self,name,age=18):
self.name=name
self.age=age
tom=Person('tom')
print (tom.__dict__['name'],tom.__dict__['age']) # 通過key調(diào)用對(duì)應(yīng)的value,此處不能調(diào)用height,因?yàn)槠洳辉趖om屬性字典中
結(jié)果如下
是類的,也是這個(gè)類所有實(shí)例的,其實(shí)例都可以訪問到,是實(shí)例的,就是這個(gè)實(shí)例自己的,通過類訪問不到。
實(shí)例可以動(dòng)態(tài)的給自己增加一個(gè)屬性,實(shí)例.dict[變量名]和實(shí)例.變量名都可以訪問到
實(shí)例的同名變量會(huì)隱藏這類變量,或者說是覆蓋了這類變量
實(shí)例屬性的查找順序
指的是實(shí)例使用.來訪問屬性,會(huì)先找到自己的dict,如果沒有。則通過屬性class找到自己的類,再去類的dict中找注意: 如果實(shí)例使用dict[變量名]訪問變量,將不會(huì)按照上面的順序查找變量了
通過類方法@classmethod 進(jìn)行將類本身調(diào)用,其中cls 關(guān)鍵字就是表示類本身,
可以使用類名.類方法(參數(shù)) 的形式進(jìn)行調(diào)用。并使用return 返回結(jié)果
1 在定義類中,使用@classmethod 裝飾器修飾的方法
2 必須至少傳遞一個(gè)參數(shù),且第一個(gè)參數(shù)留給了cls,cls指代調(diào)用者及類對(duì)象自身
3 cls這個(gè)標(biāo)識(shí)符可以是任何合法名稱,但是為了易讀,請(qǐng)不要修改
4 通過cls可以直接操作類的屬性,其無法對(duì)實(shí)例的屬性進(jìn)行修改,因?yàn)槠涞谝粋€(gè)傳遞的是類對(duì)象,類中也不能調(diào)用實(shí)例的方法
相關(guān)實(shí)現(xiàn)
#!/usr/local/bin/python3.6
#coding:utf-8
class Document: # 父類
def __init__(self,content):
self.content=content
def print(self): # 共有的屬性
print (self.content)
class Word(Document):
pass
class PrintableWord(Word):
def print(self): # 子類自己的私有屬性
print ("Word pinrt {}".format(self.content))
class Pdf(Document):
pass # 子類自定義私有屬性
print (PrintableWord.mro())
word=PrintableWord('test\nabc')
word.print()
結(jié)果如下
實(shí)例如下
#!/usr/bin/poython3.6
#conding:utf-8
class MyClass:
x='123'
@classmethod # 類方法,此處傳入的第一個(gè)值是類,cls.__name__調(diào)用的是這個(gè)類的名稱,而cls.x調(diào)用的是這個(gè)類的私有屬性
def my(cls):
cls.pas='456' # 可通過此種方式在類中增加屬性
print ('{}.x={}'.format(cls.__name__,cls.x),cls.pas)
MyClass.my() # 此處是類的自調(diào)用
a=MyClass() # 實(shí)例化,其類的相關(guān)屬性依然存在
a.my()
結(jié)果如下
1 在定義類中,使用@staticmethod 裝飾器裝飾的方法
2 調(diào)用時(shí),不會(huì)隱式傳入?yún)?shù)
3 靜態(tài)方法,只是表明這個(gè)方法屬于這個(gè)名稱空間,函數(shù)歸類在一起,方便管理組織
實(shí)例如下
#!/usr/bin/poython3.6
#conding:utf-8
class MyClass:
def char(): #此處無語(yǔ)法錯(cuò)誤,但其不建議如此寫入
print ('char')
@staticmethod # 此處是靜態(tài)方法,用于保存類中的靜態(tài)變量,其本身和實(shí)例無任何關(guān)系
def char1():
print ('char1')
a=MyClass()
# a.char() # 此處調(diào)用會(huì)出錯(cuò),但下面的由于是靜態(tài)方法,因此其調(diào)用不會(huì)出錯(cuò)
a.char1()
總結(jié): 靜態(tài)方法和類方法都屬于類的屬性
此處不推薦直接使用def char()的方式進(jìn)行處理,而推薦使用@staticmethod,python中對(duì)靜態(tài)方法的使用較少,
datetime 是在類上調(diào)用的方法,進(jìn)而造出datetime對(duì)象而返回這個(gè)方法
python中常見的三種函數(shù):
1 和實(shí)例相關(guān)的函數(shù)
2 和類相關(guān)的函數(shù)
3 一般的函數(shù)類的方法在類創(chuàng)建完成后即可進(jìn)行調(diào)用,而實(shí)例的方法在類創(chuàng)建完成之后不能調(diào)用
類的方法調(diào)用
類幾乎可以調(diào)用所有內(nèi)部定義的方法,但是調(diào)用普通的方法時(shí)會(huì)報(bào)錯(cuò),原因是第一個(gè)參數(shù)必須是類的實(shí)例
實(shí)例幾乎可以調(diào)用所有的方法,普通的函數(shù)的調(diào)用一般不可能出現(xiàn),因?yàn)椴辉试S這么定義
類方法:默認(rèn)第一個(gè)參數(shù)是類本身,其可以被類調(diào)用,不能被實(shí)例調(diào)用
普通方法:默認(rèn)第一個(gè)參數(shù)是實(shí)例本身,可以被類和實(shí)例進(jìn)行調(diào)用
靜態(tài)方法:默認(rèn)第一個(gè)參數(shù)數(shù)傳入的參數(shù)。只能被類本身進(jìn)行調(diào)用,不能被實(shí)例調(diào)用
總結(jié):
類除了普通方法外都可以調(diào)用,普通方法需要對(duì)象的實(shí)例作為第一參數(shù)
實(shí)例可以調(diào)用所有類中的方法(包括類方法,靜態(tài)方法),普通方法傳入實(shí)例自身,靜態(tài)方法和類方法需要找到實(shí)例的類后進(jìn)行相關(guān)的處理。
擴(kuò)展:
在類中調(diào)用類本身的方法:
傳統(tǒng)的輸入年、月、日、的方法:
通過函數(shù)進(jìn)行格式化的結(jié)果,通過在函數(shù)中調(diào)用類的方式實(shí)現(xiàn)
使用雙下劃線開頭的屬性名,就是私有屬性
通過在類的構(gòu)造時(shí)使用self.__x=x 來 獲取類的私有屬性。
默認(rèn)的類的私有屬性不能訪問:
通過將其私有屬性包裝成方法進(jìn)行使用,其是可以訪問的。
實(shí)例如下:
#!/usr/bin/poython3.6
#conding:utf-8
class Person:
def __init__(self,name,age):
self.name=name
self.age=age
def char(self):
if 0< self.age < 100:
return self.age
tom=Person('tom',50)
print (tom.char())
jerry=Person('jerry',110)
print (jerry.char()) # 此處的返回為空,因?yàn)闆]有滿足的條件
print (jerry.age) # 可通過此種方式進(jìn)行返回,因此其是無法真實(shí)控制的
結(jié)果如下
此處python提供了私有屬性用于解決此種問題
#!/usr/bin/poython3.6
#conding:utf-8
class Person:
def __init__(self,name,age):
self.name=name
self.__age=age # 私有屬性,隱藏之后無法使用實(shí)例名.__age進(jìn)行調(diào)用,必須將其抽象成一個(gè)方法并輸出的方式進(jìn)行處理
def char(self):
if 0< self.__age < 100:
return self.__age #
def charget(self):
return self.__age
tom=Person('tom',50)
print (tom.char())
jerry=Person('jerry',110)
# print (jerry.__age) #此處無法通過__age的方法進(jìn)行調(diào)用嗎
print (jerry.charget()) #此處可有方法進(jìn)行調(diào)用處理
print (jerry.__dict__) # 事實(shí)上,此處的私有屬性在python中是修改了名稱,其結(jié)果是實(shí)例名._類名稱__age可進(jìn)行調(diào)用,具體可參見__dict__獲取,此處私有屬性是在實(shí)例字典中存在的
print (jerry._Person__age)
jerry._Person__age=300 #修改私有屬性參數(shù)值,但其測(cè)試,顯示中既然是私有屬性,則不建議修改其屬性值
print (jerry._Person__age) # 修改結(jié)果查看
結(jié)果如下
私有變量的本質(zhì): 類定義的時(shí)候,如果聲明一個(gè)實(shí)例變量的時(shí)候,使用雙下劃線,python解釋器會(huì)將其改名,轉(zhuǎn)換成為實(shí)例名._類名__變量名,所以原來的名字訪問不到了,私有屬性是在實(shí)例的字典中的
在變量名前使用一個(gè)下劃線,稱為保護(hù)變量
#!/usr/bin/poython3.6
#conding:utf-8
class Person:
def __init__(self,name):
self._name=name # 保護(hù)變量,python開發(fā)人員約定俗稱的,不可修改的,但實(shí)際其是可以被實(shí)例調(diào)用且修改的,但建議其使用方法進(jìn)行封裝處理
def printf(self):
return self._name
tom=Person('tom')
print (tom._name)
tom._name='jerry'
print (tom.printf()) #修改后打印
結(jié)果如下
可以看出,這個(gè)_name屬性根本就沒改變名稱,和普通的屬性一樣,解釋器不做任何特殊處理,這只是開發(fā)者共同的約定,看見這種變量,就如同私有變量,不要直接使用,保護(hù)變量也是在實(shí)例的字典中的。
#!/usr/bin/poython3.6
#conding:utf-8
class Person:
def __init__(self,name):
self.name=name
def __printf(self): #私有方法,其本質(zhì)是對(duì)其名稱做了修改,其方法是類的方法是Person.__printf
return self.name
tom=Person('tom')
print (Person.__dict__)
# print (tom.__printf()) #修改后打印
print (tom.__dict__) # 實(shí)例列表中無此方法
print (tom._Person__printf()) # 此處的調(diào)用先找到實(shí)例,然后沒有這方法,然后找到類,找到該方法,
結(jié)果如下
在函數(shù)上的雙下劃線,是屬于類的屬性,方法內(nèi)部(函數(shù))的雙下劃線,是屬于實(shí)例的屬性,而不是類的屬性
私有方法的本質(zhì)
單下劃線的方法只是開發(fā)者之間的約定,解釋器不會(huì)做任何改變
雙下劃線的方法,是私有方法,解釋器會(huì)改名,改變策略和私有變量相同,但其私有變量是在實(shí)例字典中,而私有方法卻是在類字典中
私有成員總結(jié)
在python中使用單下劃線或者雙下劃綫來標(biāo)識(shí)一個(gè)成員被保護(hù)或者私有化隱藏起來,但是,不管使用什么樣的方式訪問控制,都不能真正的阻止用戶修改類的成員屬性,python中沒有絕對(duì)安全的保護(hù)成員或者私有成員因此,前面的下劃線是一種警告或者提醒,請(qǐng)遵守這個(gè)約定,除非真的必要,否則不要修改隨意使用成員保護(hù)或者私有成員。
屬性裝飾器的目的: 把實(shí)例的屬性保護(hù)起來,不讓外部直接訪問,外部使用getter讀取屬性和setter方法設(shè)置屬性。
一般方法
#!/usr/local/bin/python3.6
#coding:utf-8
class Person:
def __init__(self,name,age=18):
self.__name=name
self.age=age
def getname(self): #查看名稱的屬性
return self.__name
def setname(self,name): # 修改名稱屬性
self.__name=name
tom=Person('tom')
print (tom.getname())
tom.setname('jerry')
print (tom.getname())
結(jié)果如下
屬性裝飾器
#!/usr/local/bin/python3.6
#coding:utf-8
class Person:
def __init__(self,name,age=18):
self.__name=name
self.age=age
@property
def getname(self): #查看名稱的屬性
return self.__name
@getname.setter #修改屬性值,此處的getname和上面的和下面的必須相同,否則會(huì)出現(xiàn)錯(cuò)誤
def getname(self,value):
self.__name=value
@getname.deleter # 刪除屬性值,使用del self.__name 進(jìn)行對(duì)屬性的刪除操作
def getname(self):
#del self.__name
print ('delete self.__name')
tom=Person('tom')
print (tom.getname)
tom.getname='jerry' # 修改屬性值
print (tom.getname)
del tom.getname #外部調(diào)用執(zhí)行刪除程序
結(jié)果如下
第二種寫法
#!/usr/bin/poython3.6
#conding:utf-8
class Person:
def __init__(self,chinese,english,history):
self._chinese=chinese
self.__english=english
def seteng(self,value): # 只有g(shù)etter屬性,此中成為只讀屬性
self.__english=value
#第二種寫方式,初始化方法
eng=property(lambda self:self.__english,seteng ) # property 是只讀的,此處的傳入的值,eng是一個(gè)函數(shù),第一個(gè)是gettter,第二個(gè)是setter
stu=Person(90,100,110)
print (stu.eng)
stu.eng=200 #修改其值
print (stu.eng)
結(jié)果如下
通過此裝飾器@property: 定義一個(gè)類方法為私有屬性的名稱;讓用戶可以直接訪問, 但不能任意修改;
通過其裝飾器的方法進(jìn)行重新定義一個(gè)接受隱藏屬性的范圍來進(jìn)行修改其值。
@屬性名.seeter: 給屬性賦值時(shí)先做判斷; 當(dāng)屬性名=value會(huì)自動(dòng)調(diào)用該函數(shù)
通過deleter 方法可以使得當(dāng)del 屬性名, 會(huì)自動(dòng)調(diào)用該函數(shù)并執(zhí)行高函數(shù)下面的操作~~
特別注意: 這三個(gè)方法同名
property 裝飾器
后面跟的函數(shù)名就是以后的屬性名,它就是getter,這個(gè)必須有,有了它至少是只讀屬性setter裝飾器
與屬性名同名,且接受2個(gè)參數(shù),第一個(gè)是self,第二個(gè)是將要賦值的值,有了它,屬性可寫deleter 裝飾器
可以控制是否刪除屬性,很少用property裝飾器必須在前,setter、deleterious裝飾器在后
property 裝飾器能通過簡(jiǎn)單的方式,把對(duì)象方法的操作編程對(duì)屬性的訪問,并起到了一定的隱藏作用
@property應(yīng)用:
用于分頁(yè)顯示,此處傳入兩個(gè)值,一個(gè)值是第幾頁(yè),另一個(gè)是每頁(yè)的數(shù)量,通過@property 可以進(jìn)行對(duì)列表的操作。
類中可以定義del方法,稱為析構(gòu)函數(shù)(方法)
作用: 銷毀類的實(shí)例的時(shí)候調(diào)用,用以釋放占用的資源 ,其目標(biāo)是銷毀實(shí)例由于python實(shí)現(xiàn)了垃圾回收機(jī)制,這個(gè)方法不能確定何時(shí)使用,有必要的時(shí)候,請(qǐng)使用del語(yǔ)句刪除實(shí)例
#!/usr/bin/poython3.6
#conding:utf-8
class Person:
def __init__(self,name,age=20):
self.name=name
self.__age=age
def __del__(self): # 設(shè)置消亡實(shí)例
print ("delete instance {}".format(self.name))
a=Person('tom')
del a # 調(diào)用消亡實(shí)例
結(jié)果如下
在其他面向?qū)ο蟮母呒?jí)語(yǔ)言中,都有重載的概念,所謂的重載,就是同一個(gè)方法名,但是參數(shù)數(shù)量,類型不一樣,就是同一個(gè)方法的重載
python 沒有重載,python不需要重載
python中,方法(函數(shù))定義中,形參非常靈活,不需要指定類型,參數(shù)個(gè)數(shù)也不固定,一個(gè)函數(shù)的定義可以實(shí)現(xiàn)多種不同的形式,因此python不需要重載。
python中只要標(biāo)識(shí)符相同,則會(huì)被完全覆蓋,
1 隨機(jī)數(shù)生成類,可以指定一批生成的個(gè)數(shù),可以指定數(shù)值的范圍,生成隨機(jī)數(shù)
#!/usr/bin/poython3.6
#conding:utf-8
import random
class randsum:
@classmethod
def getsrandsum(cls,min=1,max=10,num=10):
return [random.randint(min,max) for _ in range(num)]
print (randsum.getsrandsum())
print (randsum.getsrandsum(10,20,5))
結(jié)果如下:
2 隨機(jī)生成隨機(jī)數(shù),并兩兩配對(duì)形成二維坐標(biāo)系,把這些坐標(biāo)組織起來,并進(jìn)行打印
#!/usr/bin/poython3.6
#conding:utf-8
import random
class RandomNum:
def __init__(self,count=10,min=1,max=10):
self.count=count
self.min=min
self.max=max
self.g=self._generate() # 此處可使用此種方式將內(nèi)部的方法以屬性的形式進(jìn)行處理,供內(nèi)部調(diào)用
def _generate(self):
while True:
yield [random.randint(self.min,self.max) for _ in range(self.count)] #c此處返回一個(gè)列表生成式,用于下面的next()進(jìn)行調(diào)用
def genrate(self,count):
self.count=count
return next(self.g) # 此處通過此種方式進(jìn)行處理,返回值為隨機(jī)數(shù)的單個(gè)個(gè)體
a=RandomNum()
for k,v in dict(zip(a.genrate(5),a.genrate(5))).items():
print ("(x={},y={})".format(k,v))
結(jié)果如下
3 記錄車的品牌mark,顏色color,價(jià)格 price,速度等特征,并實(shí)現(xiàn)增加車輛信息,顯示全部車輛信息的功能。
#!/usr/bin/poython3.6
#conding:utf-8
class Car:
def __init__(self,mark,speed,color,price):
self.mark=mark
self.speed=speed
self.color=color
self.price=price
class CarInfo: # 信息本身也是一個(gè)對(duì)象,一個(gè)容器的對(duì)象
def __init__(self):
self.lst = []
def addcar(self,car:Car): #此處可調(diào)用上述的類
self.lst.append(car)
def getall(self):
return self.lst # 打印的格式化輸出
ci=CarInfo()# 此處完成后,其基本的列表創(chuàng)建已經(jīng)完成
car=Car('audi',100,'red',1500000) # 此處是初始化
ci.addcar(car) # 調(diào)用此初始化數(shù)據(jù)并增加
print (ci.getall()) # 查看
可以通過修改或者替換成員,使用者調(diào)用方?jīng)]改變,但是,類提供的功能可能已經(jīng)修改了,當(dāng)項(xiàng)目需要修改較多的類時(shí),又著急上線,修改起來比較麻煩時(shí),需要通過在一個(gè)文件中指定某個(gè)類進(jìn)行相關(guān)的操作來對(duì)其進(jìn)行打補(bǔ)丁
猴子補(bǔ)丁
運(yùn)行時(shí),對(duì)屬性進(jìn)行動(dòng)態(tài)替換
黑魔法,慎用
test 源文件
#!/usr/bin/poython3.6
#conding:utf-8
class Person:
def __init__(self,chinese,english,history):
self.chinese=chinese
self.english=english
self.history=history
def getscore(self):
return (self.history,self.english,self.chinese)
a=Person(70,80,90)
print (a.getscore())
默認(rèn)結(jié)果如下
補(bǔ)丁文件
test1
#!/usr/bin/poython3.6
#conding:utf-8
def getscore(self): # 其名稱和相關(guān)的類對(duì)象名必須一致,否則會(huì)報(bào)錯(cuò),此處返回是一個(gè)字典
return dict(chi=self.chinese,eng=self.english,his=self.history)
test2
#!/usr/bin/poython3.6
#conding:utf-8
from test import Person
from test1 import getscore
def monkeypatch5Persoon():
Person.getscore=getscore # 對(duì)類來改變屬性,在類的DICT中有方法,
student = Person(80,91,80)
print (student.getscore())
monkeypatch5Persoon()
student1 = Person(80,91,80)
print (student1.getscore())
結(jié)果如下
組裝: 將數(shù)據(jù)和操作組裝到一起
隱藏?cái)?shù)據(jù):對(duì)外只暴露一些接口,通過接口訪問對(duì)象
封裝實(shí)際上是把數(shù)據(jù)封裝到摸個(gè)地方,以后再去調(diào)用在某處的內(nèi)容或者數(shù)據(jù)
調(diào)用封裝數(shù)據(jù)的方式
通過對(duì)象直接調(diào)用
其中init表示的是一個(gè)構(gòu)造器,當(dāng)類的實(shí)例化過程時(shí)會(huì)調(diào)用其方法,由于其是必選參數(shù),因此在傳值時(shí)必須與對(duì)應(yīng)的個(gè)數(shù)相同,當(dāng)然可以實(shí)例化多個(gè)對(duì)象
通過self在類內(nèi)部對(duì)類中的數(shù)據(jù)進(jìn)行調(diào)用
類的實(shí)例化
多復(fù)用,繼承來的就不用自己寫了
多繼承少修改,OCP,使用繼承來改變,來提現(xiàn)個(gè)性
基類和派生類
其中父類也叫基類
子類也叫派生類
父類
子類,其中沒有定義類的屬性和方法,只是繼承了Class1 的屬性
子類的實(shí)例化和結(jié)果,其完全繼承和父類的屬性和方法:
當(dāng)子類中有自己的構(gòu)造函數(shù)時(shí),以子類中的構(gòu)造函數(shù)為準(zhǔn)
#!/usr/bin/poython3.6
#conding:utf-8
class A:
x=123
def __init__(self,name):
self.__name=name
@property
def name(self): # 此處的A使用裝飾器將方法封裝成屬性并進(jìn)行暴露
return self.__name
def shout(self):
print ('A shout')
class B(A): #此處的B 繼承了A的屬性
x=456
def shout(self): # 此處的B對(duì)A的方法進(jìn)行了重寫
print ('B shout')
class C(B):
pass
tom=C('tom')
print (tom.name)
tom.shout()
結(jié)果如下
默認(rèn)的,私有屬性不能直接調(diào)用,需要偽裝成方法方可調(diào)用。
#!/usr/bin/poython3.6
#conding:utf-8
class A:
x=123
def __init__(self,name='tom',age=10):
self.name=name
self.__age=age
def shout(self):
print ('A shount')
@property
def getage(self):
return self.__age
class B(A):
x=456
def shout(self):
print ('B shout')
jerry=A('tom')
print (jerry.__dict__)
tom=B('jerry')
print (tom.__dict__) # 默認(rèn)的A的私有屬性會(huì)被B讀取,并可進(jìn)行訪問,其方法亦可被訪問
print (tom.getage)
結(jié)果如下
在類中,以雙下劃綫開始的方法稱為私有方法:私有方法不能繼承。
#!/usr/bin/poython3.6
#conding:utf-8
class A:
def __init__(self,name,age):
self.name=name
self.age=age
def __getname(self): #此處定義私有方法
return self.name
class B(A):
pass
b=B('tom',30)
print (b.__dict__)
print (B.__dict__)
a=A('jerry',20)
print (a.__dict__)
print (A.__dict__) # 私有方法是屬于類的,不能被繼承,
結(jié)果如下:
特殊屬性和方法 | 含義 |
---|---|
_base_ | 類的基類 |
_bases_ | 類的基類元組 |
_mro_ | 顯示方法查找順序,基類的元組 |
mor() | 同上 |
_subclasses_() | 類的子類列表 |
#!/usr/bin/poython3.6
#conding:utf-8
class A:
x=123
def __init__(self,name):
self.__name=name
@property
def name(self): # 此處的A使用裝飾器將方法封裝成屬性并進(jìn)行暴露
return self.__name
def shout(self):
print ('A shout')
class B(A): #此處的B 繼承了A的屬性
x=456
def shout(self): # 此處的B對(duì)A的方法進(jìn)行了重寫
print ('B shout')
class C(B):
pass
print (C.__base__) #顯示此類的基類
print (C.__bases__) # 顯示此類的基類,以元組呈現(xiàn)
print (C.__mro__) # 顯示類的鏈表,由此類的父類開始查找
print (C.mro()) # 通上
print (A.__subclasses__()) # 顯示此類的子類
結(jié)果如下
類和實(shí)例屬性列表打印
#!/usr/bin/poython3.6
#conding:utf-8
class A:
x=123
def __init__(self,name):
self.__name=name
@property
def name(self): # 此處的A使用裝飾器將方法封裝成屬性并進(jìn)行暴露
return self.__name
def shout(self):
print ('A shout')
class B(A): #此處的B 繼承了A的屬性
x=456
def shout(self): # 此處的B對(duì)A的方法進(jìn)行了重寫
print ('B shout')
class C(B):
pass
tom=C('tom')
print (tom.__dict__) # 打印實(shí)例的字典,其中只有實(shí)例化的屬性的列表
print (C.__dict__) # 打印C類的字典,C類無任何屬性和方法,因?yàn)槠涫莵碜杂贐和A的
print (B.__dict__) # 打印B類的字典,其中有x類屬性的定義,shout函數(shù)的定義
print (A.__dict__)# A中包括初始化函數(shù)等信息
如下
類和類屬性只有一個(gè),而實(shí)例和實(shí)例屬性卻有多個(gè)
凡是需要分成多個(gè)的,應(yīng)該設(shè)計(jì)成類的實(shí)例屬性,凡是需要一份的,應(yīng)該設(shè)計(jì)成類的屬性
一個(gè)子類繼承了祖先的特征,但祖先的都是抽象的東西,只有對(duì)象才具有繼承數(shù)據(jù)的能力,對(duì)于實(shí)例,不同的需要設(shè)置各個(gè)單獨(dú)的屬性,需要放置在自己的屬性列表中,如果需要一份,則放置在類屬性上。
A.init(self,args)
1 通過 父類名.init(self,父類參數(shù)) 進(jìn)行重寫構(gòu)造函數(shù)
通過super(自己類名稱,self).init(形參)
優(yōu)點(diǎn): 不需要明確告訴父類的名稱,如果父類改變,只需修改class 語(yǔ)句后面的繼承關(guān)系即可,不用修改父類名稱
實(shí)例化調(diào)用
#!/usr/bin/poython3.6
#conding:utf-8
class A:
x=123
def shout(self):
print ('A shout')
class B(A):
def shout(self): #此處定義覆蓋了父類的shout
print ('B')
def shout(self): # 此處定義覆蓋了自身的shout
print (super()) # 顯示super內(nèi)容
print (super(B,self))# 此處相當(dāng)于將B設(shè)置為self傳輸進(jìn)去。等價(jià)與上面的super
super().shout()#此處調(diào)用的是父類并調(diào)用了父類的shout
a=B()
a.shout()
結(jié)果如下
#!/usr/bin/poython3.6
#conding:utf-8
class A:
x=123
def __init__(self,name='tom',age=0):
self.__name=name # 此處是實(shí)例的初始化函數(shù),當(dāng)然要在其實(shí)例化后才能表現(xiàn)出該屬性,該類中也找不到,當(dāng)然在其子類中也不能找到
self.age=age
@property
def getname(self):
return self.__name
def shout(self):
print ('A shout')
class B(A):
x=456
def __init__(self,name,age):
self.age=age # 此處的傳入后會(huì)修改成50,因?yàn)槠涫窃谛薷闹髠魅階類中進(jìn)行處理的
super().__init__(name,age) #新式類推薦使用的方式,此處默認(rèn)傳入self,需要送入指定參數(shù),此處不許找指定self和父類的類名
self.__name=name+" "+'B' # 私有屬性的修改是無法生效的,因?yàn)槠渌接袑傩缘膋ey和類名相關(guān),
# self.age=10 #覆蓋共有屬性,其之前的age是0,現(xiàn)在覆蓋成10,因?yàn)閷?shí)例的字典中的key是唯一的。此處因?yàn)樵赼.__init__(self,name)之后定義,因此其會(huì)
# 覆蓋之前name傳入的值
def shout(self):
print ('B shout')
super(B,self).shout() #此處是調(diào)用父類的,通過super可以方面的訪問自己的祖先類,其查找順序是找本實(shí)例,若通過本實(shí)例查找
#其類,通過類查找其父類并進(jìn)行相關(guān)的操作
super().shout() # 與上述相同
x=B('jerry',30) # 此處傳入的值是30,由于下面的覆蓋,變成了10
x.shout()
print (x.__dict__) #其私有屬性的_A__name 仍然存在,_B__name 也存在,
print (x.getname)
結(jié)果如下
#!/usr/bin/poython3.6
#conding:utf-8
class A:
x=123
def __init__(self,name='tom',age=10):
self.name=name
self.age=age
def shout(self):
print ('A shount')
class B(A):
x=456
def __init__(self,name): #此處進(jìn)行初始化,初始化后,其父類的公有屬性將不能被調(diào)用
self.name=name #此處重新覆蓋了共有屬性name,由之前的tom修改成了jerry
def shout(self):
print ('B shout')
tom=B('jerry')
print (tom.name)
print (tom.__dict__)
#print (tom.age) # 此處是父類的屬性,此處不能被調(diào)用
結(jié)果如下
#!/usr/bin/poython3.6
#conding:utf-8
class A:
x=123
def __init__(self,name='tom',age=10):
self.name=name
self.age=age
def shout(self):
print ('A shount')
class B(A):
x=456
def __init__(self,name): #此處進(jìn)行初始化,初始化后,其父類的公有屬性將不能被調(diào)用
self.cname=name #此處定義了公有屬性cname
def shout(self):
print ('B shout')
tom=B('jerry')
print (tom.cname)
# print (tom.name) #此處是父類的屬性,不能被調(diào)用,因?yàn)樽宇愡M(jìn)行了初始化
print (tom.__dict__) # 此處只有cname
#print (tom.age) # 此處是父類的屬性,此處不能被調(diào)用
#!/usr/bin/poython3.6
#conding:utf-8
class A:
x=123
def __init__(self,name='tom'):
self.name=name
def shout(self):
print ('A shount')
class B(A):
x=456
def __init__(self,name): #此處進(jìn)行初始化,此處需要調(diào)用父類的方法,若不調(diào)用,則默認(rèn)父類的私有方法不能使用,但共有方法可以被調(diào)用
self.cname=name #此處重新定義了共有屬性cname,
A.__init__(self,name) # 此處調(diào)用了父類的name
def shout(self):
print ('B shout')
tom=B('jerry')
print (tom.name) #此處name存在于A類中。而B中調(diào)用A.__init__(self,args) 導(dǎo)致其A中存在的屬性在B中也同樣存在
print (tom.cname)
print (tom.__dict__)# 其共有方法中的name存在,也有自己的初始化的cname
結(jié)果如下
#!/usr/bin/poython3.6
#conding:utf-8
class A:
x=123
def __init__(self,name='tom',age=0):
self.__name=name
self.age=age
@property
def getname(self):
return self.__name
def shout(self):
print ('A shout')
class B(A):
x=456
def __init__(self,name,age):
#self.age=age # 此處的傳入后會(huì)修改成30,因?yàn)槠涫窃谛薷闹髠魅階類中進(jìn)行處理的
A.__init__(self,name,age) #通過父類的調(diào)用來調(diào)用父類的屬性,此中可調(diào)用父類的私有屬性,
self.__name=name+" "+'B' # 私有屬性的修改是無法生效的,因?yàn)槠渌接袑傩缘膋ey和類名相關(guān),
self.age=10 #覆蓋共有屬性,其之前的age是0,現(xiàn)在覆蓋成10,因?yàn)閷?shí)例的字典中的key是唯一的。此處因?yàn)樵赼.__init__(self,name)之后定義,因此其會(huì)
# 覆蓋之前name傳入的值
def shout(self):
print ('B shout')
x=B('jerry',30) # 此處傳入的值是30,由于下面的覆蓋,變成了10
x.shout()
print (x.__dict__) #其私有屬性的_A__name 仍然存在,_B__name 也存在,
print (x.getname)
結(jié)果如下
#!/usr/bin/poython3.6
#conding:utf-8
class A:
x=123
def __init__(self,name='tom',age=0):
self.__name=name # 此處是實(shí)例的初始化函數(shù),當(dāng)然要在其實(shí)例化后才能表現(xiàn)出該屬性,該類中也找不到,當(dāng)然在其子類中也不能找到
self.age=age
@property
def getname(self):
return self.__name
def shout(self):
print ('A shout')
class B(A):
x=456
def __init__(self,name,age):
self.age=age # 此處的傳入后會(huì)修改成50,因?yàn)槠涫窃谛薷闹髠魅階類中進(jìn)行處理的
A.__init__(self,name,age) #通過父類的調(diào)用來調(diào)用父類的屬性,此中可調(diào)用父類的私有屬性,
self.__name=name+" "+'B' # 私有屬性的修改是無法生效的,因?yàn)槠渌接袑傩缘膋ey和類名相關(guān),
# self.age=10 #覆蓋共有屬性,其之前的age是0,現(xiàn)在覆蓋成10,因?yàn)閷?shí)例的字典中的key是唯一的。此處因?yàn)樵赼.__init__(self,name)之后定義,因此其會(huì)
# 覆蓋之前name傳入的值
def shout(self):
print ('B shout')
x=B('jerry',30) # 此處傳入的值是30,由于下面的覆蓋,變成了10
x.shout()
print (x.__dict__) #其私有屬性的_A__name 仍然存在,_B__name 也存在,
print (x.getname)
結(jié)果如下
#!/usr/bin/poython3.6
#conding:utf-8
class A:
x=123
def __init__(self,name='tom',age=10):
self.name=name
self.__age=age
def shout(self):
print ('A shount')
@property
def getage(self):
return self.__age
class B(A):
x=456
def __init__(self,name,age): # 子類的初始化
self.name=name # 此處進(jìn)行覆蓋共有屬性,其私有屬性未處理
def shout(self):
print ('B shout')
b=B('jerry',30)
print (b.__dict__) # 此處只獲取到了重新定義的name,而私有屬性__age 不存在
#!/usr/bin/poython3.6
#conding:utf-8
class A:
x=123
def __init__(self,name='tom',age=10):
self.name=name
self.__age=age
def shout(self):
print ('A shount')
@property
def getage(self):
return self.__age
class B(A):
x=456
def __init__(self,name,age): # 子類的初始化
self.__age=age # 此處進(jìn)行覆蓋私有屬性,其私有屬性未處理
def shout(self):
print ('B shout')
b=B('jerry',30)
print (b.__dict__) # 此處只獲取到了重新定義的__age,而共有屬性name則不存在
結(jié)果如下
#!/usr/bin/poython3.6
#conding:utf-8
class A:
x=123
def __init__(self,name='tom',age=10):
self.name=name
self.__age=age
def shout(self):
print ('A shount')
@property
def getage(self):
return self.__age
class B(A):
x=456
def __init__(self,name,age): # 子類的初始化
A.__init__(self,name,age) #調(diào)用父類方法,處理獲取屬性
def shout(self):
print ('B shout')
b=B('jerry',30)
print (b.__dict__) # 此處可獲取父類中的共有屬性和私有屬性
print (b.name,b._A__age) # 已經(jīng)進(jìn)行了修改,,因?yàn)樯厦娴膁ef __init__(self,name,age): 中的age在實(shí)例化后已經(jīng)被修改
print (b.getage)
結(jié)果如下
#!/usr/bin/poython3.6
#conding:utf-8
class A:
x=123
def __init__(self,name='tom',age=10):
self.name=name
self.__age=age
def shout(self):
print ('A shount')
@property
def getage(self):
return self.__age
class B(A):
x=456
def __init__(self,name,age): # 子類的初始化
A.__init__(self,name,age) #調(diào)用父類方法,處理獲取屬性
self.__age=age # 重覆蓋age,但無法完成,因?yàn)槠渌接袑傩院皖惷嘘P(guān),其相當(dāng)于增加
def shout(self):
print ('B shout')
b=B('jerry',30)
print (b.__dict__) # 此處可獲取父類中的共有屬性和私有屬性
print (b.name,b._A__age) # 已經(jīng)進(jìn)行了修改,,因?yàn)樯厦娴膁ef __init__(self,name,age): 中的age在實(shí)例化后已經(jīng)被修改
print (b.getage)
結(jié)果如下
#!/usr/bin/poython3.6
#conding:utf-8
class A:
@classmethod
def class_method(cls):
print (cls.__name__) # 此處打印類的名稱
@staticmethod # 此處定義其靜態(tài)方法
def static_method():
print ('A staticmethod')
class B(A):
@classmethod
def class_method(cls):
print (cls.__name__)
@staticmethod
def static_method():
print ('B staticmethod')
class C(B):
pass
b=C()
b.class_method() # 此處因?yàn)檎{(diào)用的是C類,因此其cls.__name__打印的是C而并非是B
b.static_method() # 此處的靜態(tài)方法是B,因?yàn)镃中未定義靜態(tài)方法
print (B.__dict__)
a=A()
a.class_method() # 此處因?yàn)檎{(diào)用的時(shí)A類,因此cls.__name__打印的是A
a.static_method()
print (A.__dict__)
結(jié)果如下
靜態(tài)方法會(huì)進(jìn)行屬性查找,找到及截至,類方法因?yàn)轭惖睦^承而進(jìn)入該C類中,而C類調(diào)用其類方法后得到的名稱當(dāng)然是C自己,此處若只有A配置類屬性,則B和C進(jìn)行調(diào)用,則各自cls.name 仍然是各個(gè)實(shí)例的類,相當(dāng)于自己在調(diào)用自己的類。此處大大的復(fù)用了,此處就是多態(tài)
#!/usr/bin/poython3.6
#conding:utf-8
class A:
def __init__(self,name,age):
self.name=name
self.age=age
def __getname(self): #此處定義私有方法
return self.name
class B(A):
def __init__(self,name,age): # 此處進(jìn)行初始化,方法不能繼承
self.name=name
def __getname(self): # 此處屬于重定義私有方法
return self.age
b=B('tom',30)
print (b.__dict__)
print (B.__dict__)
a=A('jerry',20)
print (a.__dict__)
print (A.__dict__) # 私有方法是屬于類的,不能被繼承,
結(jié)果如下
原則: OCP 原則,多繼承,少修改
繼承的用途: 增強(qiáng)基類,實(shí)現(xiàn)多態(tài)多態(tài):在面向?qū)ο蟓h(huán)境中,父類,子類通過繼承聯(lián)系到一起,如果可以通過一套方法,就可以實(shí)現(xiàn)不同表現(xiàn),這就是多態(tài)
一個(gè)類繼承多個(gè)類就是多繼承,它具有多個(gè)類的特征
多態(tài)是繼承+多態(tài)
多態(tài)的弊端:
1 多繼承很好的模擬了世界,因?yàn)槭挛锖苌偈菃我焕^承,但是舍棄簡(jiǎn)單,必然引入復(fù)雜性,帶來了沖突
多繼承的實(shí)現(xiàn)會(huì)導(dǎo)致編譯器設(shè)計(jì)的復(fù)雜度增加,所以很多語(yǔ)言都舍棄了類的多繼承。多繼承可能帶來二義性
解決方案
實(shí)現(xiàn)多繼承的語(yǔ)言,需要解決二義性和,深度優(yōu)先或廣度優(yōu)先
左邊是多繼承,右邊是單繼承
多繼承帶來的路徑選擇問題
python 使用MRO(method resolution order)解決了基類搜索順序問題
歷史原因,MRO有三個(gè)搜索算法:
1 經(jīng)典算法,按照定義從左到右,深度優(yōu)先策略,2.2之前
左圖的MRO是MyClass,D,B,A,C,A
新式類算法,經(jīng)典算法的升級(jí),重復(fù)的只保留最后一個(gè)2.2
左圖的MRO是MyClass,D,B,C,A,object
C3 算法,在類被創(chuàng)建出來的時(shí)候,就計(jì)算出一個(gè)MRO有序列表,2.3之后,python3唯一支持的算法
左圖中的MRO是MyClass,D,B,C,A,object 的列表
C3 算法解決的多繼承的二義性
多繼承的缺點(diǎn)
當(dāng)類很多時(shí),繼承復(fù)雜的情況下,繼承路徑太多,很難說清什么樣的繼承路徑
Python 語(yǔ)法是允許多繼承,但python代碼是解釋器執(zhí)行的,只有執(zhí)行到的時(shí)候,才發(fā)現(xiàn)錯(cuò)誤
團(tuán)隊(duì)協(xié)作開發(fā),如果引入多繼承,代碼將不可控
不管編程語(yǔ)言是否支持多繼承,都應(yīng)當(dāng)避免多繼承
python2.x 里面支持經(jīng)典類和新式類
python3.x 里面僅支持新式類
經(jīng)典類,其可以不寫父類。
新式類,其如果沒有繼承的父類則直接寫object,必須寫父類,如果有父類,則直接寫父類
只有新式類支持mro() 方法
對(duì)于新式類,是廣度優(yōu)先
對(duì)于經(jīng)典類,是深度優(yōu)先
對(duì)于新式類,當(dāng)調(diào)用D實(shí)例時(shí),其結(jié)果是執(zhí)行D的輸出,當(dāng)D中為pass 占位,其繼承了B的輸出,當(dāng)B中的結(jié)果為pass 時(shí),其會(huì)繼承C中的輸出,
對(duì)于經(jīng)典類,當(dāng)調(diào)用D實(shí)例時(shí),其結(jié)果是執(zhí)行D的輸出,當(dāng)D中為pass 占位,其繼承了B的輸出,當(dāng)B中的結(jié)果為pass 時(shí),其會(huì)繼承A中的輸出,因?yàn)锽繼承了A,因?yàn)槠涫巧疃葍?yōu)先。
繼承時(shí),共有的,子類和實(shí)例都可以隨意訪問,私有成員被隱藏,子類和實(shí)例不可直接訪問,當(dāng)私有變量所在的類內(nèi)的方法中可以訪問這個(gè)私有變量,python通過自己一套實(shí)現(xiàn),實(shí)現(xiàn)和其他語(yǔ)言一樣的面向?qū)ο蟮睦^承機(jī)制
屬性查找順序
實(shí)例的_dict_-----類的_dict_ -----父類的_dict_,如果搜索到這些地方后沒有找到就會(huì)拋異常,先找到就立即返回了。
裝飾器: 用裝飾器裝飾一個(gè)類,把功能給類附加上去,那個(gè)類需要,就裝飾它
Mixin
文檔Document 類是其他所有文檔類的抽象基類,
Word,PDF類是Document的子類。
此處可抽象為兩種類
1 共同的特性抽象成一個(gè)類,父類
2 其他不同的特性組成其他的相關(guān)的屬性,子類
Mxin 本質(zhì)上是多繼承實(shí)現(xiàn)的
mixin 提現(xiàn)的是一種組合的設(shè)計(jì)模式
在面向?qū)ο蟮脑O(shè)計(jì)中,一個(gè)復(fù)雜的類,往往需要很多功能,而這些功能有來自不同的類提供,這些就需要很多組合在一起。
MIxin 類的使用原則:
Mixin 類中不應(yīng)該顯式的出現(xiàn)__init__初始化方法
Mixin 類通常不能獨(dú)立工作,因?yàn)樗菧?zhǔn)本混入別的類中的部分功能實(shí)現(xiàn)
Mixin 類的祖先類也應(yīng)該是Mixin類
Mixin類和裝飾器
這兩種方式都是可以使用,看個(gè)人喜好
如果需要繼承就使用MixIn類的方法
1 子類中欲實(shí)現(xiàn)自己的功能自己處理,不再父類中進(jìn)行定義
#!/usr/local/bin/python3.6
#coding:utf-8
class Document: # 父類
def __init__(self,content):
self.content=content
def print(self): # 共有的屬性
print (self.content)
class Word(Document):
pass
class PrintableWord(Word):
def print(self): # 子類自己的私有屬性
print ("Word pinrt {}".format(self.content))
class Pdf(Document):
pass # 子類自定義私有屬性
print (PrintableWord.mro())
word=PrintableWord('test\nabc')
word.print()
結(jié)果如下
2 通過父類中實(shí)現(xiàn)。子類若需要個(gè)性化需求,則自己修改
#!/usr/local/bin/python3.6
#coding:utf-8
def printable(cls): #此處傳入的是類函數(shù)
def _print(self): # 此處的實(shí)例可以看作是這個(gè)類函數(shù)的參數(shù)
print (self.content,'裝飾器') # 此處是計(jì)算的返回值
cls.print=_print # 此處對(duì)返回值進(jìn)行賦值
return cls # 并返回該函數(shù)的執(zhí)行結(jié)果
class Document:
def __init__(self,content):
self.content=content
class Word(Document):
pass
class Pdf(Document):
pass
@printable
class PrintableWord(Word): #此處先繼承,后裝飾
pass
print (PrintableWord.mro())
pw=PrintableWord('test string')
pw.print()
結(jié)果如下
另一種方式,使用lambda 進(jìn)行處理
#!/usr/local/bin/python3.6
#coding:utf-8
def printable(cls):
# 此處是給對(duì)應(yīng)的類增加相關(guān)的屬性,使得其更加健壯
cls.print=lambda self: print (self.content)
cls.NAME='name'
return cls
class Document:
def __init__(self,content):
self.content=content
class Word(Document):
pass
class Pdf(Document):
pass
@printable #先繼承,后裝飾
class PrintableWord(Word):
pass
print (PrintableWord.mro())
pw=PrintableWord('test string')
pw.print()
print (pw.NAME)
結(jié)果如下
#!/usr/bin/poython3.6
#conding:utf-8
class Docment:
def __init__(self,content):
self.content=content
def print(self):
print (self.content)
class PrintableMixin:
def print(self):
print ('*'*20)
print ('Pdf print {}'.format(self.content))
class Word(Docment):
pass
class Pdf(Docment):
pass
class PrintablePdf(PrintableMixin,Pdf): # 此處繼承了Mixin和Pdf兩個(gè)類,此處是多繼承,Mixin繼承了object。而Pdf繼承了Docment
# 而Docment 繼承了object,此處的作用是使用PrintableMixin覆蓋之前的DOcment才是要求,一般的Mixin都是在最前面放的
pass
print (PrintablePdf.mro()) #查看MRO的輸出,以MRO的輸出為準(zhǔn)
Pdf=PrintablePdf('test\nabc')
Pdf.print()
結(jié)果如下
調(diào)換位置如下
#!/usr/bin/poython3.6
#conding:utf-8
class Docment:
def __init__(self,content):
self.content=content
def print(self):
print (self.content)
class PrintableMixin:
def print(self):
print ('*'*20)
print ('Pdf print {}'.format(self.content))
class Word(Docment):
pass
class Pdf(Docment):
pass
class PrintablePdf(Pdf,PrintableMixin): # 此處繼承了Mixin和Pdf兩個(gè)類,此處是多繼承,Mixin繼承了object。而Pdf繼承了Docment
# 而Docment 繼承了object,此處的作用是使用PrintableMixin覆蓋之前的DOcment才是要求,一般的Mixin都是在最前面放的
pass
print (PrintablePdf.mro()) #查看MRO的輸出,以MRO的輸出為準(zhǔn)
Pdf=PrintablePdf('test\nabc')
Pdf.print()
結(jié)果如下:
#!/usr/bin/poython3.6
#conding:utf-8
class Docment:
def __init__(self,content):
self.content=content
def print(self):
print (self.content)
class PrintableMixin:
def print(self):
print ('*'*20)
print ('Pdf print {}'.format(self.content))
class Word(Docment):
pass
class Pdf(Docment):
pass
class SuperPrintableMixin(PrintableMixin): # 此處使用類的繼承來打印一個(gè)超類
def print(self):
print ('~'*20)
super().print()
print('~'*20)
class PrintablePdf(SuperPrintableMixin,Pdf):
pass
print (PrintablePdf.mro()) #查看MRO的輸出,以MRO的輸出為準(zhǔn)
Pdf=PrintablePdf('test\nabc')
Pdf.print()
結(jié)果如下
裝飾器使用的是函數(shù)的方式實(shí)現(xiàn)的,其函數(shù)只能實(shí)現(xiàn)封裝功能,而Mixin是一個(gè)類,其類可實(shí)現(xiàn)封裝,繼承,和多態(tài)的特性。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。