2018年12月31日 星期一

python - 繼承


甚麼是繼承?


繼承是一種創建新類的方式,在python中,新建的類可以繼承一個或多個父類,父類又可稱為基類或超類,新建的類稱為派生類或子類

class ParentClass1 : #定義父類    pass
class ParentClass2 : #定義父類    pass
class SubClass1(ParentClass1): 
#單繼承,基類是ParentClass1,派生類是SubClass    pass
class SubClass2(ParentClass1,ParentClass2):  
#python 支持多繼承,用逗號分隔開來多個繼承的類    pass

查看繼承
subclass1.__bases__#__base__只查看從左到右繼承的第一個字類,# __bases__ 則是查看所有繼承的父類(<class'__main__.ParentClass1'>,)
subclass2. __bases__
(<class'__main__.ParentClass1'>,<class'__main__.ParentClass2'>)
.提示: 如果沒有指定基類,python的類會默認繼承object 類,object 是所有python類的基類,
他提供了一些常見方法(如 ( __str__  )的實現。
ParentClass1.__bases__
(<class 'object'>,)
ParentClass2.__bases__
(<class 'object'>,)


繼承與抽象(先抽象在繼承)

抽象即抽取類似或者比較像的部分。
抽象分為兩個層次:
1.邱吉爾跟川普 兩對象比較像部分抽取成類。
2.將 人、貓、狗 這三個類比較像的部分抽取成父類。
抽取最主要的作用是劃分類別 (可以隔離關注點、降低複雜度)



繼承 : 是基於抽象的結果,通過編程語言去實現它,肯定是先經歷抽象這個過程,才能通過繼承的方式去表達出抽象的結構。
抽象只是分析和設計的過程中,一個動作或者說一種技巧,通過抽象可以得到類



繼承例子與重用性

#實際運用

例如 :
    人會 吃、喝、看電視
猴子會 吃、喝、    爬樹

現在要為 人跟猴子 創建一個類,那麼就需要為  人 跟猴子  實現他們所有個功能,方式如下:

#人跟猴子 有像似的地方

class 人 :

    def  吃(self):
             # do something

    def  喝(self):
             # do something

    def  看電視(self):
             # do something

class 猴子 :

    def  吃(self):
             # do something

    def  喝(self):
             # do something

    def  爬樹(self):
             # do something

人 跟 猴子 都有相同的功能,可以使用 繼承 把相似的部分只要書寫一次就讓猴子跟人可以使用,更改後如下:

動物: 吃、喝

人 : 看電視(人繼承動物的功能)
猴子 : 爬樹(猴子繼承動物的功能)

轉化如下:

class 動物:
def 吃(self):
#do somthing

def 喝(self):
#do somthing


# 在類後面掛號中寫入另一個類名,表示當前類繼承另外一個類,如下:
class 人(動物):

     def  看電視(self):
                 print ( '看新聞' )

class 猴子(動物):

     def  爬樹(self):
                 print ( '摘香蕉' )

#繼承 的程序實現
class Animal:
    def eat(self):
        print("%s 吃"%self.name)
    def drink(self):
        print("%s 喝" % self.name)

class People(Animal):
    def __init__(self,name):
        self.name = name
        self.breed = '人'
    def skill(self):
        print('看電視')

class Monkey(Animal):
    def __init__(self,name):
        self.name = name
        self.breed = '猴子'
    def ability(self):
        print('爬樹')

#調用
p1 = People('愛看新聞的上班族')
p1.eat()


p2 = People('愛看體育的年輕人')
p2.drink()

m1 =  Monkey('愛吃香蕉的猴子')
m1.eat()
執行結果:
愛看新聞的上班族 吃
愛看體育的年輕人 喝
愛吃香蕉的猴子 吃



.在編成的過程中,如果我們定義了一個類A,然後又想建立另外一個類B,但是類B的大部分內容與類A的相同時,我們不可能從開始寫一個類B,這就用到了類的繼承概念!
通過繼承的方式新建類B,讓B繼承A,B會 "遺傳"  A的所有屬性(數據屬性 和 函數屬性)
 實現程序重用。

class Animal :
    # 人跟猴子都是動物,所以創建一個 Animal基類    
    def __init__(self,name,aggressivity, life_value):
        self.name = name # 人跟猴都有自己的暱稱        
        self.aggressivity  = aggressivity 
        #人跟猴都有自己的攻擊力        
        self.life_value = life_value #人和猴都有自己的生命值
    def eat(self):
        print('%s is eating'%self.name)

class monkey (Animal):
    pass
class people (Animal):
    pass
egg = people('egon',10,1000)
ha2 = monkey('阿猴子',50,1000)
egg.eat()
ha2.eat()
執行結果:
egon is eating
阿猴子 is eating

.提示: 用已經有的類建立一個新的類,這樣就重用了已經有的軟體中的一部分設置大部分,大幅提升了編程工作量, 這就是常說的軟體重用, 不僅可以重用自己的類,也可以繼承別人的,比如標準庫, 來制定新的數據類型,這樣就能大大縮短了軟體開發週期,對大型軟體開發來說,意義重大。


派生

子類可以添加自己的新屬性或者在自己這裡重新定義這些屬性(不會引響到父類),須注意的是,一旦重新定義了自己的屬性且與父類相同重名,那麼調用新增的屬性時,就以自己為準。
class Animal :
    # 人跟猴子都是動物,所以創建一個 Animal基類    def __init__(self,name,aggressivity, life_value):
        self.name = name # 人跟猴都有自己的暱稱        self.aggressivity  = aggressivity #人跟猴都有自己的攻擊力        self.life_value = life_value #人和猴都有自己的生命值
    def eat(self):
        print('%s is eating'%self.name)



class monkey (Animal): #猴類,繼承Animal類    def skill(self,people):
        # 派生:猴子會攻擊人        # param people        people.life_value -=  self.aggressivity


class people (Animal):
    # 人類,繼承Animal    def attack(self,monkey):
        # 派生: 人有攻擊的能力        # param monkey        monkey.life_value -= self.aggressivity

egg  =  people('egon',10,1000)
ha2  =  monkey('吃香蕉',50,1000)
print(ha2.life_value)
print(egg.attack(ha2))
print(ha2.life_value)
執行結果:
1000
None
990
.注意: 像 ha2.life_value 之類的的屬性引用,會先從實例中找life_value然後去類中找,然後再去父類找...直到最後找頂級的父類

在子類中,新建的重名的函數屬性,在編輯函數內功能的時候,有可能需要重用父類中重名的那個函數功能,應該適用調用普通函數的方式,即: 類名.func(),此時就與調用普通函樹無異了! 因此即便是 self 參數也須要傳值.

如子類要執行父類的方法也使用super方法: (適用於pytthon 3)
方法如下:
class A :
    def  opop(self):
        print('A')

class B(A):
    def opop(self):
        super().opop()
        #super(B.self).opop()        #A.opop(self)        print('B')

a = A()
b = B()
b.opop()
super(B,b).opop()
執行結果:
A
B
A

class Animal:
    # 人跟猴 都是動物 所以創造一個Animal 基類    def __init__(self,name,aggressivity,life_value):
        self.name = name # 人跟猴 都有自己的暱稱        self.aggressivity =aggressivity
        #人和猴都有自己的攻擊力        self.life_value   = life_value
        #人跟猴 都有自己的生命值
    def eat(self):
        print('%s is eating'%self.name)

class monkey(Animal):
    #猴類 繼承Animal類    def __init__(self,name,breed,aggressivity,life_value):
        super().__init__(name,aggressivity,life_value)
        #執行父類Animal        self.bread = breed
        #派生出了新的屬性
    def bite(self,pople):
        # 派生出新的技能: 猴子有咬人的技能        # param people        pople.life_value -= self.aggressivity

    def eat(self):
        Animal.eat(self)
        print('from monkey')

class  Person(Animal):
    # 人類 繼承Animal    def __init__(self,name,aggressivity, life_value,money):
        super().__init__(name,aggressivity,life_value)
        #執行父類        self.money = money #派生出了新的屬性
    def attack(self,monkey):
      #派生出新的技能  : 人有攻擊的技能      #param monkey        monkey.life_value -= self.aggressivity

    def eat(self):
        Animal.eat(self)
        print('from Person')


egg = Person('egon',10,10000,600)
ha2 = monkey('吃香蕉','哈士奇',10,1000)
print(egg.name)
print(ha2.name)
egg.eat()
執行結果:
egon
吃香蕉
egon is eating
from Person

.通過繼承建立了派生類與基類之間的關係, 他是一種"是" 的關係,比如說 黑猴是猴,人是動物。當類之間有很多相同的功能,提取這些共同的功能做成基類,用繼承比較好,比如老闆是上司
class Boss :
    def __init__(self,name,gender):
        self.name = name
        self.gender = gender
    def teach(self):
        print('teaching')

class jobs(Boss):
    pass
p1 = jobs('egon','male')
p1.teach()
執行結果:
teaching



下面就是一個簡單的繼承例子
class Parent:
    def hello(self):
        print("正在調用父類的方法.....")


class Child(Parent):
    pass
p = Parent()
p.hello()
c = Child()
c.hello()
執行結果:
正在調用父類的方法.....
正在調用父類的方法.....




.如果子類中定義與父類同名的方法或屬性,則會覆蓋父類對應的方法或屬性。
class Parent:
    def hello(self):
        print("正在調用父類的方法.....")


class Child(Parent):
    pass
class Child(Parent):
    def hello(self):
        print("正在調用子類的方法....")


c= Child()
c.hello()
p=Parent()
p.hello()
執行結果:
正在調用子類的方法....
正在調用父類的方法.....


.以下是一個繼承的例子
import random as r


class Fish:
    def __init__(self):
        self.x = r.randint(0,10)
        self.y = r.randint(0, 10)

    def move(self):
         self.x -= 1         print("我的位置是:",self.x,self.y)

class Goldfish(Fish):
    pass
class carp(Fish):
    pass
class Salmon(Fish):
    pass
class Shark(Fish):
    def __init__(self):
        self.hungry = True
    def eat(self):
        if self.hungry:
            print("吃貨的夢想就是天天有的吃....")
            self.hungry = False        else:
            print("太撐了,吃不下了!")

fish = Fish()
fish.move()
fish.move()
goldfish =Goldfish()
goldfish.move()
goldfish.move()
goldfish.move()
shark = Shark()
shark.eat()
shark.eat()
執行結果:
我的位置是: 5 0
我的位置是: 4 0
我的位置是: 2 10
我的位置是: 1 10
我的位置是: 0 10
吃貨的夢想就是天天有的吃....
太撐了,吃不下了!


.至時候如果再調用 shark.move()  就會抱錯
原因為:
#因父類被子類覆寫過所以報錯,解決方法有兩個#1.調用為幫定的父類方法#2.使用super函數(功能為:用于调用父类(超类)的一个方法)#super也可以用來解決多重繼承、重複調用等問題



import random as r


class Fish:
    def __init__(self):
        self.x = r.randint(0,10)
        self.y = r.randint(0, 10)

    def move(self):
         self.x -= 1         print("我的位置是:",self.x,self.y)

class Goldfish(Fish):
    pass
class carp(Fish):
    pass
class Salmon(Fish):
    pass
class Shark(Fish):
    def __init__(self):
        self.hungry = True
    def eat(self):
        if self.hungry:
            print("吃貨的夢想就是天天有的吃....")
            self.hungry = False        else:
            print("太撐了,吃不下了!")

fish = Fish()
fish.move()
fish.move()
goldfish =Goldfish()
goldfish.move()
goldfish.move()
goldfish.move()
shark = Shark()
shark.eat()
shark.eat()

shark.move() #在一次調用
執行結果:
Traceback (most recent call last):
我的位置是: 1 7
我的位置是: 0 7
我的位置是: 1 8
  File "D:/python  t11/fish.py", line 44, in <module>
我的位置是: 0 8
我的位置是: -1 8
吃貨的夢想就是天天有的吃....
太撐了,吃不下了!
    shark.move() #在一次調用
  File "D:/python  t11/fish.py", line 10, in move
    self.x -= 1
AttributeError: 'Shark' object has no attribute 'x'





.下面是修改的方法
1.重新調用父類方法
import random as r


class Fish:
    def __init__(self):
        self.x = r.randint(0,10)
        self.y = r.randint(0, 10)

    def move(self):
         self.x -= 1         print("我的位置是:",self.x,self.y)

class Goldfish(Fish):
    pass
class carp(Fish):
    pass
class Salmon(Fish):
    pass
class Shark(Fish):
    def __init__(self):
        Fish.__init__(self) #寫上父類的名子        self.hungry = True
    def eat(self):
        if self.hungry:
            print("吃貨的夢想就是天天有的吃....")
            self.hungry = False        else:
            print("太撐了,吃不下了!")

fish = Fish()
fish.move()
fish.move()
goldfish =Goldfish()
goldfish.move()
goldfish.move()
goldfish.move()
shark = Shark()
shark.eat()
shark.eat()

shark.move() #在一次調用shark = Shark() #修改後再次引用shark.move()
執行結果:
我的位置是: 4 3
我的位置是: 3 3
我的位置是: 5 1
我的位置是: 4 1
我的位置是: 3 1
吃貨的夢想就是天天有的吃....
太撐了,吃不下了!
我的位置是: 2 6
我的位置是: 5 3



2.使用 shark.move() 
import random as r


class Fish:
    def __init__(self):
        self.x = r.randint(0,10)
        self.y = r.randint(0, 10)

    def move(self):
         self.x -= 1         print("我的位置是:",self.x,self.y)

class Goldfish(Fish):
    pass
class carp(Fish):
    pass
class Salmon(Fish):
    pass
class Shark(Fish):
    def __init__(self):
        super().__init__() #使用 super函數        self.hungry = True
    def eat(self):
        if self.hungry:
            print("吃貨的夢想就是天天有的吃....")
            self.hungry = False        else:
            print("太撐了,吃不下了!")

fish = Fish()
fish.move()
fish.move()
goldfish =Goldfish()
goldfish.move()
goldfish.move()
goldfish.move()
shark = Shark()
shark.eat()
shark.eat()


shark = Shark()  #已用super函數 修改shark.move()
執行結果:
我的位置是: 6 4
我的位置是: 5 4
我的位置是: -1 4
我的位置是: -2 4
我的位置是: -3 4
吃貨的夢想就是天天有的吃....
太撐了,吃不下了!
我的位置是: 8 3



.python 也可以多重繼承 class  className(Base1,Base2,Base3): .....

class Base1:
    def f1(self):
        print("我是f1,我為Base1代言...")


class Base2:
    def f2(self):
        print("我是f2,我為Base2代言...")

class C(Base1,Base2):
    pass
c = C()
c.f1()
c.f2()
執行結果:
我是f1,我為Base1代言...
我是f2,我為Base2代言...























沒有留言:

張貼留言