Python 面向對象編程OOP (二) slots,類的多態,繼承,複寫方法

__slots__魔法

你們好,上一期我重點總結了有關類的基本知識,如今簡單回顧一下,順便加上一個建立類時經常使用的東西:__slots__python

首先建立一個名人類:Celebritygit

class Celebrity:
     # 限定 Celebrity對象只能綁定name, age,domain屬性,加速
    __slots__ = ['name','age',"domain"]
    # Class Attribute
    species = 'human'
    
    # Initializer / Instance Attributes
    def __init__(self, name, age, domain):
        self.name = name
        self.age = age
        self.domain = domain

能夠發現用slots綁定了三個屬性給Celebrity,slots的做用主要有兩個:github

  • 若是須要限定自定義類型的對象只能綁定某些屬性,能夠經過在類中定義__slots__變量來進行限定。須要注意的是__slots__的限定只對當前類的對象生效,對子類並不起任何做用。
  • 加速

如今能夠作個實驗,首先咱們把slots綁定的domian屬性去掉:app

class Celebrity:
    
    # Class Attribute
    species = 'human'
    __slots__ = ['name', 'age']
    # Initializer / Instance Attributes
    def __init__(self, name, age,domain):
        self.name = name
        self.age = age
        self.domain = domain
        
female_leader = Celebrity("Miss Dong",65,"electrical appliance")

# Access the instance attributes
print("{} is {}.".format(
    female_leader.name, female_leader.age))

Out:AttributeError: 'Celebrity' object has no attribute 'domain'

會發現報錯了,即使咱們在init方法中有domain屬性,可是因爲slots中沒有,因此Celebrity類下建立的實例都不能有domaindom

接下來讓咱們簡單回顧一下如何調用類變量:函數

female_leader = Celebrity("Miss Dong", 65,"electrical appliance")
male_leader = Celebrity("Jack Ma", 55,"internet")

# Access the instance attributes
print("{} is {} and {} is {}.".format(
    female_leader.name, female_leader.age, male_leader.name, male_leader.age))

# Is male_leader a human?
if male_leader.species == "human":
    print("{0} is a {1}!".format(male_leader.name, male_leader.species))  

Out:
Miss Dong is 65 and Jack Ma is 55.
Jack Ma is a human!

*args

其實args應該和 kargs一塊兒來講,可是今天先重點看一下它在對象中的應用,咱們如今給Celebrity類新建3個實例,而且咱們想知道年齡最大的是誰 ? code

這種狀況下*args很好用:orm

a = Celebrity("Miss Dong",65,"electrical appliance")
b = Celebrity("Jack Ma", 55,"internet")
c = Celebrity("Lei Jun", 50,"mobile")

def get_oldest(*args):
    return max(args)

print("The big brother is {} years old.".format(get_oldest(a.age, b.age, c.age)))

Out:
The big brother is 65 years old.

固然,其餘的應用場景還有不少,很少列舉了對象

類的繼承

首先,咱們在Celebrity類中新增兩個方法:繼承

  • description:對生成的大佬簡單描述
  • speak: 大佬發言

完成後的結果以下:

class Celebrity:
     

    __slots__ = ['name', 'age',"domain"]
    species = 'human'

    def __init__(self, name, age, domain):
        self.name = name
        self.age = age
        self.domain = domain
        
     # instance method
    def description(self):
        return "{} is {} years old, working in the {} industry".format(self.name, self.age,self.domain)

    # instance method
    def speak(self, sound):
        return "{} says {}".format(self.name, sound)

如今新建兩個類InternetBoss,MobileBoss,所有繼承於Celebrity類:

# Child class (inherits from Dog() class)
    class InternetBoss(Celebrity):
        pass

    # Child class (inherits from Dog() class)
    class MobileBoss(Celebrity):
        pass

若是咱們什麼都不作,會自動繼承父類的 description和speak方法,作個實驗,新建li做爲InternetBoss的實例:

li = InternetBoss("Robbin",50,"advertisement")

調用description和speak方法:

li.description()
li.speak("What's your problem ?")

Out:
Robbin is 50 years old, working in the advertisement industry
Robbin says: What's your problem ?

再嘗試一個MobileBoss的對象:

lei = MobileBoss("leijun", 50,"mobile")
lei.speak("Are you ok ?")

Out:
leijun says: Are you ok ?

能夠發現都是同樣的

類的多態, 複寫父類的方法

對於類的多態,各類教程說的都太專業了,個人理解僅僅是:

  • 對父類現有方法A,當新增新的子類時,能夠根據須要重寫A。

在咱們如今的例子中,能夠複寫description方法:

class InternetBoss(Celebrity):
        def description(self):
            print("I'm Internet Boss !")
         
    class MobileBoss(Celebrity):
        def description(self):
            print("I'm Mobile phone Boss !")

這樣InternetBoss類和MobileBoss類生成實例後,會調用本身的description方法:

li = InternetBoss("Robbin",50,"advertisement")
lei = MobileBoss("leijun", 50,"mobile")

li.description()
lei.description()

Out:
I'm Internet Boss !
I'm Mobile phone Boss !

isinstance() 和 issubclass()

Python 有兩個判斷繼承的函數:

  • isinstance() 用於檢查實例類型
  • issubclass() 用於檢查類繼承

如今還用咱們的例子說明一下,首先,這是咱們現有的三個類:

class Celebrity:
    __slots__ = ['name', 'age',"domain"]
    species = 'human'

    def __init__(self, name, age, domain):
        self.name = name
        self.age = age
        self.domain = domain
        
    def description(self):
        print( "{} is {} years old, working in the {} industry".format(self.name, self.age,self.domain))

    def speak(self, sound):
        print("{} says: {}".format(self.name, sound))
        
        
        
class InternetBoss(Celebrity):
    def description(self):
        print("I'm Internet Boss !")
         
class MobileBoss(Celebrity):
    def description(self):
        print("I'm Mobile phone Boss !")

而後咱們分別用不一樣的類建立三個實例:

mingzhu = Celebrity("Miss Dong",65,"electrical appliance")
ma= InternetBoss("Pony", 48,"internet")
lei = MobileBoss("leijun", 50,"mobile")

如今使用issubclass()判斷InternetBoss和MobileBoss是否繼承自Celebrity:

# True
issubclass(InternetBoss,Celebrity) 

# True
issubclass(MobileBoss,Celebrity)

使用isinstance()查看mingzhu究竟是誰的實例:

# True
isinstance(mingzhu,Celebrity)

# False
isinstance(mingzhu,InternetBoss)

# False
isinstance(mingzhu,MobileBoss)

同理查看ma究竟是哪一個類的實例:

# True
isinstance(ma,Celebrity)

# True
isinstance(ma,InternetBoss)

# False
isinstance(ma,MobileBoss)

由於InternetBoss是Celebrity子類,因此ma同時是Celebrity和InternetBoss的實例。

若是咱們混用了issubclass和isinstance,會報錯:

issubclass(ma,InternetBoss)

Out:
TypeError: issubclass() arg 1 must be a class

子類重寫構造函數

剛纔提到了,若是子類沒有寫構造函數init(),會自動繼承父類的init,但咱們一般須要子類有不一樣的初始函數,這樣咱們就須要本身複寫一下,這裏以InternetBoss爲例:

class InternetBoss(Celebrity):
    def __init__(self,name, age, domain,hometown):
        super().__init__(name, age, domain)
        self.hometown = hometown
        
    
    def description(self):
        print("I'm Internet Boss !")
        
    def __repr__(self):
        return f"This is {self.name} speaking !"

使用了super()會保留須要的父類初始化參數,再添加本身的就好了,這裏的repr我會下次總結,如今再新建實例:

總結

此次我記錄了slots用法,*args 的一個使用場景,類的繼承,複寫父類方法,構造函數等基本概念,剩下的慢慢來,我會一點點補充。。。

Ps: 本文的實例名稱均爲杜撰,請不要對號入座...

個人其餘文章已經放到了Github上,若是感興趣的朋友能夠去看看,連接以下:

相關文章
相關標籤/搜索