python之繼承、抽象類、新式類和經典類

1、上節補充
一、靜態屬性
靜態屬性 : 類的屬性,全部的對象共享這個變量
  若是用對象名去修改類的靜態屬性:在對象的空間中又建立了一個屬性,而不能修改類中屬性的值
  操做靜態屬性應該用類名來操做java

例1:請你寫一個類,可以統計一共實例化了多少個對象?python

複製代碼
class Foo:
    count = 0
    def __init__(self):
        Foo.count += 1

f1 = Foo()
print(f1.count)       # 1
f2 = Foo()
f3 = Foo()
f4 = Foo()
f5 = Foo()
print(f1.count)       # 5
print(f5.count)       # 5
print(Foo.count)    # 5
複製代碼

結論:當類中的屬性發生改變的時候,對象中沒有同名的屬性、方法的時候,對象使用屬性名會跟着類中的變量走算法

 

例二:(類的靜態屬性爲可變數據類型,對象也能引用並修改)編程

複製代碼
class Foo:
    count = [0]

f1 = Foo()
f1.count[0] += 1   # 靜態屬性的修改  1
print(f1.count[0]) # 對象引用類的靜態屬性 1
print(Foo.count[0]) # 類修改後 也是 1
f1.count = [2]    # 對象新增 2
print(f1.count)   # 2
print(Foo.count)  # 類不變 1
複製代碼

結論:
1,類的靜態屬性是可變數據類型時,對象能夠引用並修改
2,只要對象的某個屬性被直接賦值,那麼必定是對象的命名空間發生變化
3,只要是靜態變量,就用類名操做python3.x

 


(面向對象的三大特性:繼承、多態、封裝,這裏先說一下繼承)
2、繼承(提升代碼的重用性,規範性)微信

(C語言沒有面向對象,而java和C#只有單繼承沒有多繼承(可是有接口),
python和C++有單繼承也有多繼承(python本來並無接口,可是有些人爲python開發了接口模塊,因此在python中,
須要用接口的時候要安裝特定的模塊))函數


2-1單繼承:
1,語法:
class A:
  passpost

class B(A):
  pass微信支付

這就是單繼承:
  A就叫:父類/超類/基類
  B就叫:子類/派生類this


2,繼承與重用:子類可使用父類中的變量和方法
下面看個例子瞭解一下:
咱們都知道貓有本身的名字和吃的糧食,還有貓會喝水吃東西,抓老鼠等,
狗也有本身的名字和吃的糧食,狗也會喝水吃東西,狗還能看家等。
所以構建出來的類以下:

複製代碼
class Cat():
    def __init__(self,name,food):
        self.name = name
        self.food = food

    def eat(self):
        print('吃貓糧')

    def drink(self):
        print('喝水')
        
    def catch_mouse(self):
        print('抓老鼠')



class Dog():
    def __init__(self,name,food):
        self.name = name
        self.food = food

    def eat(self):
        print('吃狗糧')

    def drink(self):
        print('喝水')
    
    def look_after_house(self):
        print('看家')

xiaomao = Cat('啊貓','貓糧')
print(xiaomao.name)         #啊貓
xiaomao.eat()                     #吃貓糧
xiaomao.catch_mouse()   #抓老鼠

xiaogou = Dog('啊狗','狗糧')
print(xiaogou.name)       #啊狗
xiaogou.eat()                  #吃狗糧
xiaogou.look_after_house()   #看家
複製代碼

這麼一看是否是感受代碼有不少重複的地方,好比初始化名字和食物、吃東西和喝水的方法,
那麼怎麼樣能夠節省代碼呢?這就要用到繼承。
咱們先定義一個公共的類Animal,用來存儲貓和狗相同的方法和屬性。貓類和狗類分別繼承Animal類,
就能夠繼承Animal的屬性和方法了。

 

複製代碼
class Animal:
    def __init__(self,name,food):
        self.name = name
        self.food = food

    def eat(self):
        print('吃%s'%(self.food))

    def drink(self):
        print('喝水')


class Cat(Animal):

    def catch_mouse(self):
        print('抓老鼠')


class Dog(Animal):

    def look_after_house(self):
        print('看家')

xiaomao = Cat('啊貓','貓糧')
print(xiaomao.name)         #啊貓
xiaomao.eat()                     #吃貓糧
xiaomao.catch_mouse()   #抓老鼠

xiaogou = Dog('啊狗','狗糧')
print(xiaogou.name)       #啊狗
xiaogou.eat()                  #吃狗糧
xiaogou.look_after_house()   #看家
複製代碼

 

這樣一來是否是就簡化了不少,並且再來一個豬類,只要它也是有這些公共方法,它也能繼承Animal類,
一會兒就能夠節省了不少代碼。

其中:
父類/超類/基類 :Animal
子類/派生類 :Cat、Dog

 

3,繼承與派生:
(1)繼承:提升代碼的重用性,規範代碼
(2)派生:子類在父類的基礎上又新建立了本身須要的方法和屬性
(3)父類有的而子類沒有:子類對象直接調用 就會直接執行父類的方法
(4)父類有的而子類也有:一、子類對象調用 直接執行子類中的方法
            二、想在子類中使用父類的名字:父類名、super()去調用

 例如:

 

複製代碼
class Animal:
    def __init__(self, name, food):
        self.name = name
        self.food = food

    def eat(self):
        print('吃%s' % (self.food))

    def drink(self):
        print('喝水')


class Cat(Animal):  # Animal的派生類
    def __init__(self, name, food, eye_color):
        self.eye_color = eye_color  # 派生屬性
        super().__init__(name, food)
        # Animal.__init__(self,name,food) 跟上一句super()都是調用父類的方法
        # 不一樣的是super()不須要傳self,而直接用父類名.方法(),須要傳self

    def catch_mouse(self):  # 派生方法
        print('抓老鼠')

    def eat(self):   # 不只執行了父類中的基礎功能,還完成了特殊的功能
        Animal.eat(self)
        # super().eat()
        self.weight = 10


class Dog(Animal):
    def look_after_house(self):
        print('看家')

    def eat(self):
        # Animal.eat(self)
        super().eat()
        self.drink()  # 吃完東西調用父類喝水的方法


xiaomao = Cat('阿貓', '貓糧', '綠色')  
print(xiaomao.eye_color)  # 綠色
print(xiaomao.food)  #貓糧
xiaomao.catch_mouse() #抓老鼠
xiaomao.eat()  #吃貓糧
print(xiaomao.weight)  # 10

xiaogou = Dog('啊狗', '狗糧') 
xiaogou.eat()  #吃狗糧  喝水
複製代碼

 

 

 

2-2多繼承:
1,語法:
class A:
  pass

class B:
  pass

class C(A,B):
  pass

C既繼承了A,又繼承了B


2,實例:

複製代碼
# 天鵝:飛 游泳 走路
# 老虎:走路 游泳
# 鸚鵡:飛 說話 走路

class Animal:
    def __init__(self,name):
        self.name = name

class FlyAnimal(Animal):  #會飛的動物類
    def fly(self):
        print('%s在飛' % self.name)

class WalkAnimal(Animal):  #會走路的動物類
    def walk(self): 
        print('%s在走路'%self.name)

class SwimAnimal(Animal):  #會游泳的動物類
    def swim(self):
        print('%s在游泳'%self.name)

class Tiger(SwimAnimal,WalkAnimal):  # 老虎
    pass

class Swan(SwimAnimal,WalkAnimal,FlyAnimal):  # 天鵝
    pass

class Parrot(FlyAnimal,WalkAnimal):  # 鸚鵡
    def talk(self):
        print('%s說話了'%self.name)

swan = Swan('天鵝')
swan.fly()  # 天鵝在飛
swan.walk()  # 天鵝在走路
複製代碼

 

 

 

 

3、抽象類:抽象類是一個規範,它基本不會實現什麼具體的功能,只能被繼承,不能被實例化
一、抽象類的做用:規範編程模式
  多人開發、複雜的需求、後期的擴展
  是一種用來幫助咱們完成規範化的手段

二、如何定義抽象類
  1,from abc import ABCMeta,abstractmethod
  2,在這個類建立的時候指定 metaclass = ABCMeta
  3,在你但願子類要實現的方法的上一行加上一個 @abstractmethod裝飾器

三、使用抽象類
  1,繼承這個類
  2,必須實現這個類中被@abstractmethod裝飾器裝飾的方法

四、實例

複製代碼
# 支付功能

from abc import ABCMeta, abstractmethod
class Payment(metaclass=ABCMeta):  # 模板的功能
    @abstractmethod                # abstractmethod是一個裝飾器,裝飾器怎麼用?放在函數或者類的上一行
    def pay(self): pass

# 這樣就構建了一個抽象類Payment,並聲明瞭子類必需要實現的方法是 pay(),若子類沒有定義pay(),則實例化時會報錯


class Alipay(Payment):  # 繼承了抽象類,就必須實現抽象類中被@abstractmethod裝飾器裝飾的方法 pay()
    def pay(self, money):
        print('使用支付寶支付了%s元' % money)


class Wechatpay(Payment):
    def pay(self, money):
        print('使用微信支付了%s元' % money)


class My_pay(Payment):  # 這裏沒有定義pay()方法,那麼在實例化的時候機會報錯
    def fuqian(self,money):
        print('你支付了%s元' % money)


def pay(obj, money):
    obj.pay(money)


# p = Payment()  # 報錯 抽象類不能被實例化

a = Alipay()
# a.pay(100)
pay(a,100)  # 使用支付寶支付了100元

we = Wechatpay()
# we.pay(200)
pay(we,200)  # 使用微信支付了200元

my = My_pay()  # 報錯:類中沒有定義抽象類的pay方法
pay(my,300)
複製代碼

 

 

 

 

4、新式類
一、新式類和經典類:
繼承了object的類就是新式類
在py3中默認都繼承了object所以全部的類都是新式類
在py2中既有新式類又有經典類


python3.x:
在python3.x版本中全部的類都是新式類
全部的新式類都有一個默認的父類 : object

class Person1:pass
class Person2():pass
class Person3(object):pass
# __bases__方法是查看某個類繼承的全部父類
print(Person1.__bases__)  # (<class 'object'>,)
print(Person2.__bases__)  # (<class 'object'>,)
print(Person3.__bases__)  # (<class 'object'>,)

 

python 2.7:
經典類和新式類並存
class Student:pass # 經典類
class Student(object):pass # 新式類

class Person1:pass # 經典類
class Person2():pass #經典類
class Person3(object):pass #新式類


二、多繼承的順序(在新式類和經典類之間的區別)
新式類
  全部的多繼承關係尋找方法的順序 :遵循廣度優先算法
  繼承object
  類名.mro() # (返回一個類的尋找順序(繼承順序)的列表)
  super : super不是單純的找父類,而是遵循mro順序的

 

經典類
  python2.x
  不主動繼承object
  經典類在找父類中方法的過程當中遵循:深度優先算法
  不提供mro方法和super

 

2-一、新式類中

複製代碼
class A:
    def func(self):
        print('A')

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

class C(A):
    def func(self):
        super().func()
        print('C')

class D(B,C):
    def func(self):
        super().func()
        print('D')
print(D.mro())     # [<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
D().func()         # A C B D
複製代碼

 

 

 

 

 

複製代碼
class A:
    pass

class B(A):
    pass

class C(A):
    pass

class D(B):
    pass

class E(C):
    pass

class F(D,E):
    pass

print(F.mro())
結果:
# [<class '__main__.F'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>,
<class '__main__.A'>, <class 'object'>]
複製代碼

 

 

 

相關文章
相關標籤/搜索