__import__ 反射和面向?qū)ο蠡A(chǔ) self 封裝 繼承(多繼承的順序)

一记盒、反射

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>

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)
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末愧膀,一起剝皮案震驚了整個濱河市拦键,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌檩淋,老刑警劉巖芬为,帶你破解...
    沈念sama閱讀 211,290評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件萄金,死亡現(xiàn)場離奇詭異,居然都是意外死亡媚朦,警方通過查閱死者的電腦和手機氧敢,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,107評論 2 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來询张,“玉大人孙乖,你說我怎么就攤上這事》菅酰” “怎么了唯袄?”我有些...
    開封第一講書人閱讀 156,872評論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長蜗帜。 經(jīng)常有香客問我恋拷,道長,這世上最難降的妖魔是什么厅缺? 我笑而不...
    開封第一講書人閱讀 56,415評論 1 283
  • 正文 為了忘掉前任蔬顾,我火速辦了婚禮,結(jié)果婚禮上湘捎,老公的妹妹穿的比我還像新娘阎抒。我一直安慰自己,他們只是感情好消痛,可當(dāng)我...
    茶點故事閱讀 65,453評論 6 385
  • 文/花漫 我一把揭開白布且叁。 她就那樣靜靜地躺著,像睡著了一般秩伞。 火紅的嫁衣襯著肌膚如雪逞带。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,784評論 1 290
  • 那天纱新,我揣著相機與錄音展氓,去河邊找鬼。 笑死脸爱,一個胖子當(dāng)著我的面吹牛遇汞,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播簿废,決...
    沈念sama閱讀 38,927評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼空入,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了族檬?” 一聲冷哼從身側(cè)響起歪赢,我...
    開封第一講書人閱讀 37,691評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎单料,沒想到半個月后埋凯,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體点楼,經(jīng)...
    沈念sama閱讀 44,137評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,472評論 2 326
  • 正文 我和宋清朗相戀三年白对,在試婚紗的時候發(fā)現(xiàn)自己被綠了掠廓。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,622評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡甩恼,死狀恐怖蟀瞧,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情媳拴,我是刑警寧澤黄橘,帶...
    沈念sama閱讀 34,289評論 4 329
  • 正文 年R本政府宣布兆览,位于F島的核電站屈溉,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏抬探。R本人自食惡果不足惜子巾,卻給世界環(huán)境...
    茶點故事閱讀 39,887評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望小压。 院中可真熱鬧线梗,春花似錦、人聲如沸怠益。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蜻牢。三九已至烤咧,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間抢呆,已是汗流浹背煮嫌。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留抱虐,地道東北人昌阿。 一個月前我還...
    沈念sama閱讀 46,316評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像恳邀,于是被迫代替她去往敵國和親懦冰。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,490評論 2 348

推薦閱讀更多精彩內(nèi)容