一记盒、反射
python中的反射功能是由以下四個內(nèi)置函數(shù)提供:hasattr、getattr慷丽、setattr蹦哼、delattr,該四個函數(shù)分別用于對對象內(nèi)部執(zhí)行:檢查是否含有某成員要糊、獲取成員翔怎、設(shè)置成員、刪除成員杨耙。
反射:
通過字符串的形式導(dǎo)入模塊
通過字符串的形式赤套,去模塊中尋找指定的函數(shù)梅誓,并執(zhí)行
_ import _(字符串) 將字符串作為模塊名導(dǎo)入 ,賦值的話就相當(dāng)于 as
反射:
根據(jù)字符串的形式取某個模塊中尋找東西
根據(jù)字符串的形式取某個模塊中判斷東西是否存在
根據(jù)字符串的形式去某個模中設(shè)置東西
根據(jù)字符串的形式取某個模塊中刪除的東西
根據(jù)字符串的形式去對象(某個模塊)中操作其成員
class Foo(object):
def __init__(self):
self.name = 'wupeiqi'
def func(self):
return 'func'
obj = Foo()
# #### 檢查是否含有成員 ####
hasattr(obj, 'name')
hasattr(obj, 'func')
# #### 獲取成員 ####
getattr(obj, 'name')
getattr(obj, 'func')
# #### 設(shè)置成員 ####
setattr(obj, 'age', 18)
setattr(obj, 'show', lambda num: num + 1)
# #### 刪除成員 ####
delattr(obj, 'name')
delattr(obj, 'func')
1._ import _("模塊名的字符串")
from 包 import 模塊名 as 別名 ===等價于=== 別名 = _ import _("模塊名的字符串")
#!/usr/bin/env python
# _*_ coding:utf-8 _*_
__author__ = 'liujianzuo'
def f1():
return "f1"
def f2():
return "f2"
def f3():
return "f3"
# 正常導(dǎo)入
import commons as CC # == 特殊導(dǎo)入(字符串導(dǎo)入) DD = __import__("commons")
ret = commons.f1()
print(ret)
1.1 特殊import情況
針對該模塊同一級下有另一個目錄寻拂,也就是包,而這個包下有另一個包估盘,而我們需要導(dǎo)入的模塊還在其下面车柠,這時候剔氏,不能應(yīng)用包.包.模塊作為字符串傳入_ import _來導(dǎo)入了塑猖,因為其只會導(dǎo)入第一層包。需要加入一個參數(shù) fromlist=True
_ import _("a.b.c.file.login",fromlist=True)
擴展:
導(dǎo)入模塊
#單層
a = __import__("模塊名")
# 多層
#當(dāng)前目錄下有好幾層
#1
from a.b.c.file import login
#2
__import__("a.b.c.file.login") #是不對的 只導(dǎo)入了a目錄 包
正確寫法:
__import__("a.b.c.file.login",fromlist=True)
2谈跛、getattr反射 可以傳入字符串獲取變量名或者函數(shù)
#!/usr/bin/env python
# _*_ coding:utf-8 _*_
# 正常導(dǎo)入
import commons as CC # == 特殊導(dǎo)入(字符串導(dǎo)入) DD = __import__("commons")
ret = CC.f1()
print(ret)
# 應(yīng)用
# 根據(jù)用戶輸入字符串羊苟,將字符串作為模塊名導(dǎo)入并應(yīng)用其內(nèi)的方法
mod_name = input("請輸入模塊:").strip()
print(mod_name,type(mod_name))
DD = __import__(mod_name) #通過字符串形式導(dǎo)入模塊
# ret = DD.f1() #正常調(diào)用 模塊中尋找函數(shù),并執(zhí)行
fuc_name = input("請輸入執(zhí)行的函數(shù):")
ret=getattr(DD,fuc_name)()
print(ret)
3 hasattr 反射 可以傳入字符串判斷模塊是否有這個 變量名或函數(shù)
# 正常導(dǎo)入
import commons as CC # == 特殊導(dǎo)入(字符串導(dǎo)入) DD = __import__("commons")
ret = commons.f1()
print(ret)
# 應(yīng)用
# 根據(jù)用戶輸入字符串感憾,將字符串作為模塊名導(dǎo)入并應(yīng)用其內(nèi)的方法
mod_name = input("請輸入模塊:").strip()
print(mod_name,type(mod_name))
DD = __import__(mod_name) #通過字符串形式導(dǎo)入模塊
# ret = DD.f1() #正常調(diào)用 模塊中尋找函數(shù)蜡励,并執(zhí)行
fuc_name = input("請輸入執(zhí)行的函數(shù):")
if hasattr(DD,fuc_name):
ret=getattr(DD,fuc_name)()
print(ret)
4 簡寫 輸入url尾部判斷,反射執(zhí)行不同的模塊的不同函數(shù)
from lib import account
inp_url = input("請輸入url:")
#
# if inp_url.endswith("login"):
# print(account.login())
# elif inp_url.endswith("logout"):
# print(account.logout())
#
# else:
# print(account.nb())
#防止出現(xiàn)不能用的場景
# 1
# inp = inp_url.split("/")[-1]
# if hasattr(account,inp):
# ret = getattr(account,inp)
# print(ret())
# else:
# print(404)
# 2 擴展1
target_module,target_func = inp_url.split("/")
m = __import__("lib."+target_module,fromlist=True)
if hasattr(m,target_func):
ret = getattr(m,target_func)
print(ret())
else:
print(404)
5 反射的四中方法介紹
getattr
#1
import commons
target_func = getattr(commons,"f1")
target_func()
#2
DD = __import__("commons)
target_func = getattr(DD,"f1")
# 設(shè)置默認(rèn)值阻桅,沒有找到為默認(rèn)值
target_func = getattr(DD,"f1"凉倚,None)
# 還可以獲取全局變量
str_ = getattr(DD,"name",None)
target_func
hasattr
# 判斷 函數(shù)或變量存在與否, true or false
r= hasattr(commons,"name")
setattr
設(shè)置 變量或者定義函數(shù)
fuc = setattr(commons,"f4", lambda x:x+2)
str_s = setattr(commons,"name", "alex")
delattr
刪除 變量或者定義函數(shù)
f = delattr(commons,"name")
2.對象
詳細(xì)解析:
當(dāng)我們要訪問一個對象的成員時嫂沉,應(yīng)該是這樣操作
class Foo(object):
def __init__(self):
self.name = 'alex'
def func(self):
return 'func'
obj = Foo()
# 訪問字段(屬性)
obj.name
# 執(zhí)行方法
obj.func()
那么問題來了稽寒?
a、上述訪問對象成員的 name 和 func 是什么趟章?
答:是變量名
b杏糙、obj.xxx 是什么意思?
答:obj.xxx 表示去obj中或類中尋找變量名 xxx蚓土,并獲取對應(yīng)內(nèi)存地址中的內(nèi)容宏侍。
c、需求:請使用其他方式獲取obj對象中的name變量指向內(nèi)存中的值 “alex”
class Foo(object):
def __init__(self):
self.name = 'alex'
# 不允許使用 obj.name
obj = Foo()
答:有兩種方式北戏,如下:
class Foo(object):
def __init__(self):
self.name = 'alex'
def func(self):
return 'func'
# 不允許使用 obj.name
obj = Foo()
print obj.__dict__['name']
class Foo(object):
def __init__(self):
self.name = 'alex'
def func(self):
return 'func'
# 不允許使用 obj.name
obj = Foo()
print getattr(obj, 'name')
d、比較三種訪問方式
- obj.name
- obj._ dict _['name']
- getattr(obj, 'name')
答:第一種和其他種比漫蛔,...
第二種和第三種比嗜愈,...
from wsgiref.simple_server import make_server
class Handler(object):
def index(self):
return 'index'
def news(self):
return 'news'
def RunServer(environ, start_response):
start_response('200 OK', [('Content-Type', 'text/html')])
url = environ['PATH_INFO']
temp = url.split('/')[1]
obj = Handler()
is_exist = hasattr(obj, temp)
if is_exist:
func = getattr(obj, temp)
ret = func()
return ret
else:
return '404 not found'
if __name__ == '__main__':
httpd = make_server('', 8001, RunServer)
print "Serving HTTP on port 8000..."
httpd.serve_forever()
結(jié)論:反射是通過字符串的形式操作對象相關(guān)的成員。一切事物都是對象CЧ辍H浼蕖!
import sys
def s1():
print 's1'
def s2():
print 's2'
this_module = sys.modules[__name__]
hasattr(this_module, 's1')
getattr(this_module, 's2')
類也是對象
class Foo(object):
staticField = "old boy"
def __init__(self):
self.name = 'wupeiqi'
def func(self):
return 'func'
@staticmethod
def bar():
return 'bar'
print getattr(Foo, 'staticField')
print getattr(Foo, 'func')
print getattr(Foo, 'bar')
模塊也是對象
"""
程序目錄:
home.py
index.py
當(dāng)前文件:
index.py
"""
import home as obj
#obj.dev()
func = getattr(obj, 'dev')
func()
三毯盈、面向?qū)ο?/h2>
面向?qū)ο?
面向?qū)ο蟛皇撬星闆r都適用
類里面的方法都不屬于 模塊了剃毒,而是屬于類。
class Oldboy:
def fetch(self,backend):
pass
def add_record(self,backend,record):
pass
obj = Oldboy() #實例化類搂赋,創(chuàng)建obj
obj.techt("www.oldboy.org")
obj.add_record("www.oldboy.org",XXXXXXX)
面向?qū)ο缶幊?/h3>
面向?qū)ο?
面向?qū)ο蟛皇撬星闆r都適用
類里面的方法都不屬于 模塊了剃毒,而是屬于類。
class Oldboy:
def fetch(self,backend):
pass
def add_record(self,backend,record):
pass
obj = Oldboy() #實例化類搂赋,創(chuàng)建obj
obj.techt("www.oldboy.org")
obj.add_record("www.oldboy.org",XXXXXXX)
a 定義類
class 類名:
def 方法一(self,參數(shù)一赘阀,參數(shù)二):
pass
b 根據(jù)類創(chuàng)建對象
使用對象執(zhí)行類中的方法
1、面向?qū)ο蟮膕elf 解釋
寫在前面:self其實就是對象名脑奠,實例化成什么對象基公,self就代表什么對象
self: 對象名
調(diào)用方法的時候,python默認(rèn)會把對象實例 賦值個self傳入方法
# 打印self的內(nèi)存地址
class Oldboy(object):
def fecht(self,backend):
print(backend,self)
def add_record(self,backend,record):
pass
"""rf
self: 對象名
調(diào)用方法的時候宋欺,python默認(rèn)會把對象實例 賦值個self傳入 方法
"""
obj1 = Oldboy()
print("obj1:",obj1) #obj1: <__main__.Oldboy object at 0x0000000000B41400>
obj1.fecht("bbbbackend") #bbbbackend <__main__.Oldboy object at 0x0000000000B41400>
面向?qū)ο蟾攀觯?
- 面向過程:根據(jù)業(yè)務(wù)邏輯從上到下壘代碼
- 函數(shù)式編程:將某些功能的代碼封裝到函數(shù)中轰豆,日后便無需重復(fù)寫胰伍,僅調(diào)用函數(shù)即可
- 面向?qū)ο缶幊蹋簩瘮?shù)進行分類封裝,讓開發(fā)‘更快酸休、更好骂租、更強’
面向過程編程最易被初學(xué)者接收,其往往用一段長代碼來實現(xiàn)指定功能斑司,開發(fā)過程中最常見的操作就是復(fù)制粘貼
while True:
if cpu利用率 > 90%:
#發(fā)送郵件提醒
連接郵箱服務(wù)器
發(fā)送郵件
關(guān)閉連接
if 硬盤使用空間 > 90%:
#發(fā)送郵件提醒
連接郵箱服務(wù)器
發(fā)送郵件
關(guān)閉連接
if 內(nèi)存占用 > 80%:
#發(fā)送郵件提醒
連接郵箱服務(wù)器
發(fā)送郵件
關(guān)閉連接
隨著時間的推移渗饮,開始使用了函數(shù)式編程,增強代碼的重用性和可讀性陡厘,就變成了這樣
def 發(fā)送郵件(內(nèi)容)
#發(fā)送郵件提醒
連接郵箱服務(wù)器
發(fā)送郵件
關(guān)閉連接
while True:
if cpu利用率 > 90%:
發(fā)送郵件('CPU報警')
if 硬盤使用空間 > 90%:
發(fā)送郵件('硬盤報警')
if 內(nèi)存占用 > 80%:
發(fā)送郵件('內(nèi)存報警')
2抽米、創(chuàng)建類和對象
構(gòu)造方法 __ init __
類+括號, ====》 自動執(zhí)行類中的 __init__方法糙置;創(chuàng)建了一個對象
在 __init__ 方法中執(zhí)行具體封裝的操作
__init__ 有一個特殊的名字: 構(gòu)造方法
=====>>>> 初始化
__del__解釋器銷毀對象的時候自動調(diào)用云茸,特殊的名字: 析構(gòu)方法
利用構(gòu)造方法 封裝 因為類實例化為對象默認(rèn)執(zhí)行init構(gòu)造方法
class Oldboy2(object):
def __init__(self,bk):
self.name = "alex" #直接封裝一個變量到self內(nèi),而self則生成那個對象就等于哪個對象谤饭,作為所有對象的公共參數(shù)
self.backend = bk # 這個封裝是針對不同對象實例傳入不同的參數(shù)标捺,而進行的封裝,屬于各自對象揉抵,默認(rèn)實例化傳入?yún)?shù)亡容,self為對象名,而bk是參數(shù)冤今,而這里又將參數(shù)封裝給self.backend闺兢,而self等于 對象,所以將backend封裝給了對象
def fecht(self):
print(self.backend)
def add_record(self,backend,record):
pass
obj2 = Oldboy2("www.obj2.org")
obj2.fecht()
obj3 = Oldboy2("www.obj3.org")
obj3.fecht()
面向?qū)ο缶幊淌且环N編程方式戏罢,此編程方式的落地需要使用 “類” 和 “對象” 來實現(xiàn)屋谭,所以,面向?qū)ο缶幊唐鋵嵕褪菍?“類” 和 “對象” 的使用龟糕。
類就是一個模板桐磁,模板里可以包含多個函數(shù),函數(shù)里實現(xiàn)一些功能
對象則是根據(jù)模板創(chuàng)建的實例讲岁,通過實例對象可以執(zhí)行類中的函數(shù)
- class是關(guān)鍵字我擂,表示類
- 創(chuàng)建對象,類名稱后加括號即可
ps:類中的函數(shù)第一個參數(shù)必須是self(詳細(xì)見:類的三大特性之封裝)類中定義的函數(shù)叫做 “方法”
# 創(chuàng)建類
class Foo:
def Bar(self):
print 'Bar'
def Hello(self, name):
print 'i am %s' %name
# 根據(jù)類Foo創(chuàng)建對象obj
obj = Foo()
obj.Bar() #執(zhí)行Bar方法
obj.Hello('wupeiqi') #執(zhí)行Hello方法
誒,你在這里是不是有疑問了车猬?使用函數(shù)式編程和面向?qū)ο缶幊谭绞絹韴?zhí)行一個“方法”時函數(shù)要比面向?qū)ο蠛啽?/p>
- 面向?qū)ο螅骸緞?chuàng)建對象】【通過對象執(zhí)行方法】
- 函數(shù)編程:【執(zhí)行函數(shù)】
觀察上述對比答案則是肯定的珠闰,然后并非絕對伏嗜,場景的不同適合其的編程方式也不同挣轨。
總結(jié):函數(shù)式的應(yīng)用場景 --> 各個函數(shù)之間是獨立且無共用的數(shù)據(jù)
三、面向?qū)ο蟮娜筇卣?封裝摩幔、繼承鞭铆、多態(tài))
1澄港、封裝
使用場景:當(dāng)同一類型的方法具有形同參數(shù)時候祖搓,直接封裝到對象即可
使用場景:把類當(dāng)做模板藏姐,創(chuàng)建多個對象()
封裝羔杨,顧名思義就是將內(nèi)容封裝到某個地方举庶,以后再去調(diào)用被封裝在某處的內(nèi)容添祸。
所以,在使用面向?qū)ο蟮姆庋b特性時寻仗,需要:
- 將內(nèi)容封裝到某處
-
從某處調(diào)用被封裝的內(nèi)容
---第一步:將內(nèi)容封裝到某處---
self 是一個形式參數(shù)刃泌,當(dāng)執(zhí)行 obj1 = Foo('wupeiqi', 18 ) 時
self 等于 obj1 當(dāng)執(zhí)行 obj2 = Foo('alex', 78 ) 時,self 等于 obj2
所以署尤,內(nèi)容其實被封裝到了對象 obj1 和 obj2 中耙替,每個對象中都有 name 和 age 屬性,在內(nèi)存里類似于下圖來保存曹体。
---第二步:從某處調(diào)用被封裝的內(nèi)容---
調(diào)用被封裝的內(nèi)容時俗扇,有兩種情況:
- 通過對象直接調(diào)用
- 通過self間接調(diào)用
1、通過對象直接調(diào)用被封裝的內(nèi)容
上圖展示了對象 obj1 和 obj2 在內(nèi)存中保存的方式箕别,根據(jù)保存格式可以如此調(diào)用被封裝的內(nèi)容:對象.屬性名
class Foo:
def __init__(self, name, age):
self.name = name
self.age = age
obj1 = Foo('wupeiqi', 18)
print obj1.name # 直接調(diào)用obj1對象的name屬性
print obj1.age # 直接調(diào)用obj1對象的age屬性
obj2 = Foo('alex', 73)
print obj2.name # 直接調(diào)用obj2對象的name屬性
print obj2.age # 直接調(diào)用obj2對象的age屬性
# 1封裝 封裝參數(shù)到對象里面铜幽,而 self == 對應(yīng)的對象名 所以對象.變量 可以通過self.變量調(diào)取
class Oldboy1(object):
def fecht(self):
print(self.backend)
def add_record(self,backend,record):
pass
obj2 = Oldboy1()
obj2.backend="www.obj2.org" #封裝到對象里面的變量
obj2.fecht()
obj3 = Oldboy1()
obj3.backend="www.obj3.org"
obj3.fecht()
如上代碼 第一種 封裝 封裝參數(shù)到對象里面,而 self == 對應(yīng)的對象名 所以對象.變量 可以通過self.變量調(diào)取
如下代碼第二種封裝 利用構(gòu)造方法 封裝 因為類實例化為對象默認(rèn)執(zhí)行init構(gòu)造方法
# 2 利用構(gòu)造方法 封裝 因為類實例化為對象默認(rèn)執(zhí)行init構(gòu)造方法
class Oldboy2(object):
def __init__(self,bk):
self.name = "alex" #直接封裝一個變量到self內(nèi)串稀,而self則生成那個對象就等于哪個對象除抛,作為所有對象的公共參數(shù)
self.backend = bk # 這個封裝是針對不同對象實例傳入不同的參數(shù),而進行的封裝母截,屬于各自對象到忽,默認(rèn)實例化傳入?yún)?shù),self為對象名清寇,而bk是參數(shù)喘漏,而這里又將參數(shù)封裝給self.backend护蝶,而self等于 對象,所以將backend封裝給了對象
def fecht(self):
print(self.backend)
def add_record(self,backend,record):
pass
obj2 = Oldboy2("www.obj2.org")
obj2.fecht()
obj3 = Oldboy2("www.obj3.org")
obj3.fecht()
2翩迈、通過self間接調(diào)用被封裝的內(nèi)容
執(zhí)行類中的方法時滓走,需要通過self間接調(diào)用被封裝的內(nèi)容
class Foo:
def __init__(self, name, age):
self.name = name
self.age = age
def detail(self):
print self.name
print self.age
obj1 = Foo('wupeiqi', 18)
obj1.detail() # Python默認(rèn)會將obj1傳給self參數(shù),即:obj1.detail(obj1)帽馋,所以搅方,此時方法內(nèi)部的 self = obj1,即:self.name 是 wupeiqi 绽族;self.age 是 18
obj2 = Foo('alex', 73)
obj2.detail() # Python默認(rèn)會將obj2傳給self參數(shù)姨涡,即:obj1.detail(obj2),所以吧慢,此時方法內(nèi)部的 self = obj2涛漂,即:self.name 是 alex ; self.age 是 78
綜上所述检诗,對于面向?qū)ο蟮姆庋b來說匈仗,其實就是使用構(gòu)造方法將內(nèi)容封裝到 對象 中,然后通過對象直接或者self間接獲取被封裝的內(nèi)容逢慌。
二悠轩、繼承
繼承,面向?qū)ο笾械睦^承和現(xiàn)實生活中的繼承相同攻泼,即:子可以繼承父的內(nèi)容火架。
例如:
貓可以:喵喵叫、吃忙菠、喝何鸡、拉、撒
狗可以:汪汪叫牛欢、吃骡男、喝、拉傍睹、撒
如果我們要分別為貓和狗創(chuàng)建一個類隔盛,那么就需要為 貓 和 狗 實現(xiàn)他們所有的功能,如下所示:
偽代碼
class 貓:
def 喵喵叫(self):
print '喵喵叫'
def 吃(self):
# do something
def 喝(self):
# do something
def 拉(self):
# do something
def 撒(self):
# do something
class 狗:
def 汪汪叫(self):
print '喵喵叫'
def 吃(self):
# do something
def 喝(self):
# do something
def 拉(self):
# do something
def 撒(self):
# do something
上述代碼不難看出焰望,吃骚亿、喝已亥、拉熊赖、撒是貓和狗都具有的功能,而我們卻分別的貓和狗的類中編寫了兩次虑椎。如果使用 繼承 的思想震鹉,如下實現(xiàn):
動物:吃俱笛、喝、拉传趾、撒
貓:喵喵叫(貓繼承動物的功能)
狗:汪汪叫(狗繼承動物的功能)
偽代碼
class 動物:
def 吃(self):
# do something
def 喝(self):
# do something
def 拉(self):
# do something
def 撒(self):
# do something
# 在類后面括號中寫入另外一個類名迎膜,表示當(dāng)前類繼承另外一個類
class 貓(動物):
def 喵喵叫(self):
print '喵喵叫'
# 在類后面括號中寫入另外一個類名,表示當(dāng)前類繼承另外一個類
class 狗(動物):
def 汪汪叫(self):
print '喵喵叫'
class Animal:
def eat(self):
print "%s 吃 " %self.name
def drink(self):
print "%s 喝 " %self.name
def shit(self):
print "%s 拉 " %self.name
def pee(self):
print "%s 撒 " %self.name
class Cat(Animal):
def __init__(self, name):
self.name = name
self.breed = '貓'
def cry(self):
print '喵喵叫'
class Dog(Animal):
def __init__(self, name):
self.name = name
self.breed = '狗'
def cry(self):
print '汪汪叫'
# ######### 執(zhí)行 #########
c1 = Cat('小白家的小黑貓')
c1.eat()
c2 = Cat('小黑的小白貓')
c2.drink()
d1 = Dog('胖子家的小瘦狗')
d1.eat()
所以浆兰,對于面向?qū)ο蟮睦^承來說磕仅,其實就是將多個類共有的方法提取到父類中,子類僅需繼承父類而不必一一實現(xiàn)每個方法簸呈。
注:除了子類和父類的稱謂榕订,你可能看到過 派生類 和 基類 ,他們與子類和父類只是叫法不同而已蜕便。
學(xué)習(xí)了繼承的寫法之后劫恒,我們用代碼來是上述阿貓阿狗的功能:
class Animal:
def eat(self):
print "%s 吃 " %self.name
def drink(self):
print "%s 喝 " %self.name
def shit(self):
print "%s 拉 " %self.name
def pee(self):
print "%s 撒 " %self.name
class Cat(Animal):
def __init__(self, name):
self.name = name
self.breed = '貓'
def cry(self):
print '喵喵叫'
class Dog(Animal):
def __init__(self, name):
self.name = name
self.breed = '狗'
def cry(self):
print '汪汪叫'
# ######### 執(zhí)行 #########
c1 = Cat('小白家的小黑貓')
c1.eat()
c2 = Cat('小黑的小白貓')
c2.drink()
d1 = Dog('胖子家的小瘦狗')
d1.eat()
2.1 繼承的兩種情況
繼承:
1 子類可以用父類的所有方法
父類 == 基類
子類 == 派生類
2.派生類和子類中都有同一個方法,調(diào)用派生類時候優(yōu)先執(zhí)行派生類的方法
3 多繼承
派生類可以繼承多個類轿腺,這在c# 和java是不可以的
可以多個父類的所有功能
優(yōu)先級:從左到右两嘴,如果本身派生類中有就優(yōu)先執(zhí)行本身的功能
派生類中沒有基類的功能:
# 1 派生類中沒有基類的功能:
class Animals:
def chi(self):
print("chi")
def he(self):
print("he")
class Cat(Animals):
def __init__(self,name):
self.Name = name
def jiao(self):
print("%s 叫"%(self.Name))
class Dog(Animals):
def __init__(self,name):
self.Name = name
def jiao(self):
print("%s 叫"%(self.Name))
mao1 = Cat("小花")
mao1.jiao()
派生類中有的功能 基類中也有
派生類中有的功能 基類中也有 : 優(yōu)先執(zhí)行派生類中的方法。 即從上到下
class Animals:
def chi(self):
print("chi")
def he(self):
print("he")
def piao(self):
print("%s 票 小澤瑪利亞" % self.Name)
class Cat(Animals):
def __init__(self,name):
self.Name = name
def jiao(self):
print("%s 叫"%(self.Name))
def piao(self):
print("%s 票 蒼井空" % self.Name)
class Dog(Animals):
def __init__(self,name):
self.Name = name
def jiao(self):
print("%s 叫"%(self.Name))
mao1 = Cat("小花")
mao1.piao()
2.2 多繼承的情況 1
多繼承族壳,1 從左到右去匹配憔辫,匹配到就不向右匹配了, 2 派生類中有的就不用了
# 多繼承仿荆,1 從左到右去匹配螺垢,匹配到就不向右匹配了, 2 派生類中有的就不用了
class Animals:
def chi(self):
print("chi")
def he(self):
print("he")
def piao(self):
print("%s 票 小澤瑪利亞" % self.Name)
class Dog_F():
def __init__(self,name):
self.Name = name
def jiao(self):
print("%s 叫"%(self.Name))
def piao(self):
print("%s 票 蒼井空" % self.Name)
class Dog(Animals,Dog_F):
def __init__(self,name):
self.Name = name
def jiao(self):
print("%s 叫"%(self.Name))
dog1 = Dog("小強")
dog1.piao()
2.3 多繼承的混亂點python3版本的兩種情況
1 第一種情況 頂級 a b 都是單獨的情況
e 繼承 c d c繼承a d 繼承b
"""
e執(zhí)行方法赖歌,如果e中沒有枉圃,從左到右依次找,c中有就執(zhí)行c的庐冯,
c中沒有的話就會去c的父類a中找孽亲,a中沒有的話,返回e的第二個父類d中找展父,
d中沒有的話返劲,去d的父類b中找
"""
class A:
def f1(self):
print("a")
class B:
def f1(self):
print("b")
class C(A):
def f(self):
print("c")
class D(B):
def f1(self):
print("d")
class E(C,D):
def f(self):
print("e")
obj = E()
obj.f1()
2 第二種個情況 頂級a b 類都繼承同一個父類
e 繼承 c d c繼承a d 繼承b a b 都繼承 z
"""
e執(zhí)行方法,如果e中沒有栖茉,從左到右依次找篮绿,c中有就執(zhí)行c的,
c中沒有的話就會去c的父類a中找吕漂,a中沒有的話,不會去a b 共同的父類z中找亲配,
而是 返回e的第二個父類d中找,
d中沒有的話,去d的父類b中找吼虎,b中沒有的話犬钢,去a b 共同的父類z中找
"""
# 第二種情況
class Z:
def f1(self):
print("a")
class A(Z):
def f(self):
print("a")
class B(Z):
def f1(self):
print("b")
class C(A):
def f(self):
print("c")
class D(B):
def f1(self):
print("d")
class E(C,D):
def f(self):
print("e")
obj = E()
obj.f1()
python2版本 多繼承問題
經(jīng)典類 :直系找到底在從開始兄弟類開始
新式類:同py3一樣
頂級a b 類都繼承同一個父類
e 繼承 c d c繼承a d 繼承b a b 都繼承 z
經(jīng)典類 直系找到底
如下尋找路徑 e -c -a -z -d -b
class Z:
def f1(self):
print('z')
class A(Z):
def f1(self):
print("a")
class B(Z):
def f1(self):
print("b")
class C(A):
def f(self):
print("c")
class D(B):
def f1(self):
print("d")
class E(C, D):
def f(self):
print("e")
obj = E()
obj.f1()
那么問題又來了,多繼承呢思灰?
- 是否可以繼承多個類
-
如果繼承的多個類每個類中都定了相同的函數(shù)玷犹,那么那一個會被使用呢?
1洒疚、Python的類可以繼承多個類歹颓,Java和C#中則只能繼承一個類
2、Python的類如果繼承了多個類油湖,那么其尋找方法的方式有兩種晴股,分別是:深度優(yōu)先和廣度優(yōu)先
- 當(dāng)類是經(jīng)典類時,多繼承情況下肺魁,會按照深度優(yōu)先方式查找
-
當(dāng)類是新式類時电湘,多繼承情況下,會按照廣度優(yōu)先方式查找
經(jīng)典類和新式類鹅经,從字面上可以看出一個老一個新寂呛,新的必然包含了跟多的功能,也是之后推薦的寫法瘾晃,從寫法上區(qū)分的話贷痪,如果 當(dāng)前類或者父類繼承了object類,那么該類便是新式類蹦误,否則便是經(jīng)典類劫拢。
class D:
def bar(self):
print 'D.bar'
class C(D):
def bar(self):
print 'C.bar'
class B(D):
def bar(self):
print 'B.bar'
class A(B, C):
def bar(self):
print 'A.bar'
a = A()
# 執(zhí)行bar方法時
# 首先去A類中查找,如果A類中沒有强胰,則繼續(xù)去B類中找舱沧,如果B類中么有,則繼續(xù)去D類中找偶洋,如果D類中么有熟吏,則繼續(xù)去C類中找,如果還是未找到玄窝,則報錯
# 所以牵寺,查找順序:A --> B --> D --> C
# 在上述查找bar方法的過程中,一旦找到恩脂,則尋找過程立即中斷帽氓,便不會再繼續(xù)找了
a.bar()
class D(object):
def bar(self):
print 'D.bar'
class C(D):
def bar(self):
print 'C.bar'
class B(D):
def bar(self):
print 'B.bar'
class A(B, C):
def bar(self):
print 'A.bar'
a = A()
# 執(zhí)行bar方法時
# 首先去A類中查找,如果A類中沒有俩块,則繼續(xù)去B類中找黎休,如果B類中么有浓领,則繼續(xù)去C類中找,如果C類中么有奋渔,則繼續(xù)去D類中找,如果還是未找到壮啊,則報錯
# 所以嫉鲸,查找順序:A --> B --> C --> D
# 在上述查找bar方法的過程中,一旦找到歹啼,則尋找過程立即中斷玄渗,便不會再繼續(xù)找了
a.bar()
經(jīng)典類:首先去A類中查找,如果A類中沒有狸眼,則繼續(xù)去B類中找藤树,如果B類中么有,則繼續(xù)去D類中找拓萌,如果D類中么有岁钓,則繼續(xù)去C類中找,如果還是未找到微王,則報錯
新式類:首先去A類中查找屡限,如果A類中沒有,則繼續(xù)去B類中找炕倘,如果B類中么有钧大,則繼續(xù)去C類中找,如果C類中么有罩旋,則繼續(xù)去D類中找啊央,如果還是未找到,則報錯
注意:在上述查找過程中涨醋,一旦找到瓜饥,則尋找過程立即中斷,便不會再繼續(xù)找了
總結(jié)
以上就是本節(jié)對于面向?qū)ο蟪跫壷R的介紹浴骂,總結(jié)如下:
- 面向?qū)ο笫且环N編程方式压固,此編程方式的實現(xiàn)是基于對 類 和 對象 的使用
- 類 是一個模板,模板中包裝了多個“函數(shù)”供使用
- 對象靠闭,根據(jù)模板創(chuàng)建的實例(即:對象)帐我,實例用于調(diào)用被包裝在類中的函數(shù)
- 面向?qū)ο笕筇匦裕悍庋b、繼承和多態(tài)