1. 程式人生 > >面向物件中的繼承

面向物件中的繼承

面向物件中的三大特性(所有語言通用)

繼承

多型

封裝


 

繼承的目的:為了解決類與類之間程式碼重複的問題

類的繼承的語法:
單繼承
class A:pass
class B(A):pass
print(B.__bases__)
在定義類的時候加(),括號寫的類就是繼承的類
B類繼承A類
A類 : 父類 基類 超類
B類 : 子類 派生類
多繼承(python支援 java不支援)
class C:pass
class D:pass
class E(C,D):pass
print(E.__bases__)
E繼承C,D
C,D都是父類
E是子類
 
使用繼承這個概念的過程
class Animal:

def __init__(self,name,kind,language):
self.name = name
self.kind = kind
self.language = language
def eat(self):
print('%s is eating'%self.name)
def drink(self):
print('%s is drinking'%self.name)
def yell(self):
print('%s say %s'%(self.name,self.language))

class Cat(Animal):pass
class Dog(Animal):pass
小花 = Cat('小花','金吉拉','喵喵')
小黑 = Dog('小黑','土狗','旺旺')
小花.yell()
小黑.yell()
print(小花.name)
print(小花.kind)
子類可以繼承父類的方法和屬性
例項化的執行流程:
先開闢一塊空間,並且空間中已經有了一個類指標,指向Cat
執行__init__方法,在Cat類的空間中沒有init方法,找Animal類中的init
將空間返回給小花變數
繼承
子類呼叫方法,如果子類自己有用自己的,用了自己的就不用父類的了
如果子類自己沒有才呼叫父類的


對於有不同的方法
class Animal:
def __init__(self,name,kind,language):
self.name = name
self.kind = kind
self.language = language
def eat(self):
print('%s is eating'%self.name)
def drink(self):
print('%s is drinking'%self.name)
def yell(self):
print('%s say %s'%(self.name,self.language))
class Cat(Animal):
def climb(self): # 派生方法
print('%s can climb'%self.name)
class Dog(Animal): # 派生方法
def lookafter_door(self):
print('%s can look after door'%self.name)
小花 = Cat('小花','金吉拉','喵喵')
小黑 = Dog('小黑','土狗','旺旺')
小花.climb()
小黑.lookafter_door()

animal_1 = Animal('大金魚','魚','吐泡泡')
animal_1.climb() # 報錯

繼承

子類呼叫方法,如果子類自己有用自己的,用了自己的就不用父類的了
如果子類自己沒有才呼叫父類的
如果子類有個性化的父類沒有的方法,可以單獨定義在子類中 - 派生方法
只有子類能夠使用父類中的方法,父類不可以使用子類中的方法
具體的例子:


class Animal:
def __init__(self,name,kind,language):
self.name = name
self.kind = kind
self.language = language
def eat(self):
print('%s is eating'%self.name)
def drink(self):
print('%s is drinking'%self.name)
def yell(self):
print('%s say %s'%(self.name,self.language))
def sleep(self):
print('%s 在睡覺'%self.name)
class Cat(Animal):
def climb(self): # 派生方法
print('%s can climb'%self.name)
def sleep(self):
#1. Animal.sleep(self) # 父類名,主動傳self
#super(self,Cat).sleep() # 過程 super(self,子類名).方法名()
#2. super().sleep() # super().方法名()
print('團著睡')
class Dog(Animal): # 派生方法
def lookafter_door(self):
print('%s can look after door'%self.name)

小花 = Cat('小花','金吉拉','喵喵')
小花.sleep() # 既希望走父類的基礎的sleep,又希望走自己的方法

當某一個方法,父類和子類都擁有的時候,那麼在子類的方法中,呼叫父類的同名方法
1.父類名.方法名(self,...)
2.super().sleep(...)

 
總結:
繼承
兩種語法:
單繼承
多繼承
幾個基礎概念
父類 : 超類 基類
子類 : 派生類
為什麼要繼承 : 幾個類之間有重複的屬性/方法 ,就把相同的屬性和方法抽象出來,作為父類,子類去繼承父類
父類和子類之間的關係 : 子類關聯父類,父類並不關聯子類
子類使用父類的方法
子類中有,父類中沒有 : 用子類的
父類中有,子類中沒有 : 用父類的
子類\父類中都有 : 預設情況下用子類的不用父類的
既想用父類又想用子類 : 父類名.方法名(子類物件),super().方法名()
子類\父類中都沒有 : 報錯


抽象類: from abc import ABCMeta,abstractmethod
舉例說明:
from abc import ABCMeta,abstractmethod
class Payment(metaclass=ABCMeta):
@abstractmethod #規定支付功能
def pay(self):pass

@abstractmethod #規定退款功能
def back(self): pass

class AliPay(Payment):
def __init__(self,name):
self.name = name
def pay(self,money):
print('%s通過支付寶消費了%s元'%(self.name,money))
def back(self,tk):
print('%s通過支付寶退款了%s元'%(self.name,tk))

class WeChatPay(Payment):
def __init__(self,name):
self.name = name
def pay(self,money):
print('%s通過微信消費了%s元'%(self.name,money))
def back(self,tk):
print('%s通過微信退款%s元'%(self.name,tk))

class ApplePay(Payment):
def __init__(self,name):
self.name = name
def pay(self,money):
print('%s通過蘋果消費了%s元'%(self.name,money))
def back(self,tk):
print('%s通過蘋果退款%s元'%(self.name,tk))

def pay_func(person,payway,money,tk):
if payway == 'alipay':
per = AliPay(person)
elif payway == 'wechatpay':
per = WeChatPay(person)
elif payway == 'applepay':
per = ApplePay(person)
per.pay(money)
per.back(tk)

pay_func('張飛','alipay',200,100)
pay_func('關羽','wechatpay',300,100)
pay_func('劉備','applepay',4200,100)主要是解決同事協作之間的程式碼規範問題
規定:(上例中)Payment 就是一個規範類,這個類存在的意義不在於實現實際的功能,而是為了約束所有的子類必須實現pay的方法
Payment : 抽象類
pay = Payment() # 抽象類: 不能例項化
抽象類主要就是作為基類/父類,來約束子類中必須實現的某些方法
抽象類的特點:
     from abc import ABCMeta,abstractmethod
        必須在類定義的時候指定metaclass = ABCMeta
必須在要約束的方法上方加上@abstractmethod方法
粗略使用:
from abc import ABCMeta,abstractmethod #(抽象方法)
class Payment(metaclass=ABCMeta): # metaclass 元類 metaclass = ABCMeta表示Payment類是一個規範類
@abstractmethod # @abstractmethod表示下面一行中的pay方法是一個必須在子類中實現的方法
def pay(self):pass

@abstractmethod
def back(self):pass # 退款功能

class ApplePay(Payment):
def pay(self):
pass
def back(self):
pass

介面類:
java 不支援多繼承
python 支援多繼承 :通過抽象類的多繼承來實現複雜的規範
不同動物的相同行為是不能混為一談
不同動物的相同行為的方法名字是必須一樣

python
抽象類 : 抽象類中的方法可以寫一些具體的py程式碼(規範)
單繼承
多繼承

java
不支援多繼承,新的概念 介面 Interface
和抽象類幾乎一模一樣的功能 :
只定義一個介面名字(基類名),內部定義子類必須實現的方法
介面支援多繼承
介面內部的所有方法都不能寫具體的程式碼,只能用pass代替

抽象類 :
單繼承的形容,並且在單繼承中可以在方法中寫python程式碼
介面類 : 更接近java中的介面的概念
python中由於有了抽象類的多繼承,不需要介面的概念了
一個基類寫出來被子類多繼承了 : 介面類
並且在方法中只寫pass(你可以選擇性的滿足)

 

案例說明
動物園
天鵝 : 飛 走 游泳
老虎 : 走 游泳
鸚鵡 : 飛 走 說話
from abc import ABCMeta,abstractmethod
class Fly_Animal(metaclass=ABCMeta):
@abstractmethod
def fly(self):
print('爺會飛')
class Swim_Animal(metaclass=ABCMeta):
@abstractmethod
def swim(self): pass
class Walk_Animal(metaclass=ABCMeta):
@abstractmethod
def walk(self): pass

class Swan(Fly_Animal,Swim_Animal,Walk_Animal):
def fly(self):
super().fly()
print('飛')
def walk(self):print('走')
def swim(self):print('遊')

class Tiger(Walk_Animal,Swim_Animal):
def walk(self):print('走')
def swim(self):print('遊')

class Parrot(Fly_Animal,Walk_Animal):
def fly(self):print('飛')
def walk(self):print('走')
def talk(self):print('說')

多繼承:
python2 :兩種類
python3 :只有一種類
新式類 : 預設繼承object類 # object 是所有類的父類
為什麼可以不寫__init__?
所有object中的類都是你自己不寫也可以呼叫的
區別
鑽石繼承問題/多繼承的優先順序問題
在python3中 所有的類都是新式類,所有的新式類的繼承順序都遵循C3演算法,也叫廣度優先演算法
可以使用類名.__mro__()這個方法來檢視這個繼承順序


案例說明:
class A:
pass
def func(self):print('A')

class B(A):
pass
def func(self):print('B')

class C(A):
pass
def func(self):print('C')

class D(B):
pass
def func(self):print('D')

class E(C):
pass
def func(self):print('E')

class F(D,E):
pass
# def func(self):print('F')
f= F()
f.func()



C3演算法 - 鑽石模型
每一個類的繼承順醋都是從基類向子類看
形成一個指向關係的順序[當前類]+[父類的繼承順序]
進行一個提取
如果一個類出現在從左到右的第一個順序上
並且沒有出現在後面順序中
或者出現在後面的順序中了但是仍然是第一個,
那麼就把這個類提取出來
L(A) = [A] + [O]
A = [O]
L(A) = AO

L(B) = [B] + [AO]
B = [AO]
BA = [O]
L(B) = [BAO]

L(C) = [C] + [AO]
C = [AO]
CA = [O]
L[C] = [CAO]

L[D] = [D] + [BAO] + [CAO]
D = [BAO] + [CAO]
DB = [AO] + [CAO]
DBC = [AO] + [AO]
DBCA = [O] + [O]
L[D] = DBCAO