Python基礎-類與物件

不該相遇在秋天發表於2020-07-13

類的基本使用

class Person():
    def __init__(self,name,age):
        self.name = name
        self.age = age

    def info(self):
        print(f'大家好,我是{self.name},我今年{self.age}歲了')


xiaohua = Person('小花',21)
xiaohua.info()

列印結果:

大家好,我是小花,我今年21歲了

 

python裡面的類,架子大概就是這個樣子,__init__就是建構函式,所有的方法的第一個形參都是self,這個不是關鍵字,命名為self是行業預設寫法,你把self改成abc也行,重點是第一個形參,進來的都是當前例項物件,對標其他程式語言的this。

 

屬性的存取

正常存取

python裡面沒有私有屬性這個東西,預設全部都是public

class Person():
    def __init__(self,name,age):
        self.name = name
        self.age = age

    def info(self):
        print(f'大家好,我是{self.name},我今年{self.age}歲了')


xiaohua = Person('小花',21)
print(f'年齡是:{xiaohua.age}')
xiaohua.age = 22
print(f'改變後的年齡是:{xiaohua.age}')

列印結果:

年齡是:21
改變後的年齡是:22

 

存取器

python的存取器實際上是用了小花招,它允許你定義屬性或者方法的名字前面加上兩個下劃線,它會對這種格式的名稱進行轉換,轉換後名稱也就變了,外部就訪問不到該屬性,所以就有了私有屬性的效果。

class Person():
    def __init__(self,name,age):
        self.__name = name
        self.__age = age

    def info(self):
        print(f'大家好,我是{self.__name},我今年{self.__age}歲了')


xiaohua = Person('小花',21)
xiaohua.info()
print(f'年齡是:{xiaohua.__age}')

 

xiaohua.info()這一行是可以正常列印出資訊,但是下面一行就會報錯,報錯原因是沒有__age這個屬性。

我們鑑於這種玩法,就可以做出存取器方法

class Person():
    def __init__(self,name,age):
        self.__name = name
        self.__age = age

    def info(self):
        print(f'大家好,我是{self.__name},我今年{self.__age}歲了')

    def get_age(self):
        return self.__age

    def set_age(self,age):
        self.__age = age

xiaohua = Person('小花',21)
xiaohua.info()
xiaohua.set_age(23)
xiaohua.info()

列印結果:

大家好,我是小花,我今年21歲了
大家好,我是小花,我今年23歲了

 

但是事實上,私有屬性只能成為一種程式設計師之間的約定,它是攔不住人的,因為python把帶兩個下劃線打頭的屬性轉換後的結果是有規則的,它會轉換成一個下劃線+類名+原屬性名。

class Person():
    def __init__(self,name,age):
        self.__name = name
        self.__age = age

    def info(self):
        print(f'大家好,我是{self.__name},我今年{self.__age}歲了')

    def get_age(self):
        return self.__age

    def set_age(self,age):
        self.__age = age


xiaohua = Person('小花',21)
xiaohua.info()
xiaohua._Person__age = 22
xiaohua.info()

列印結果:

大家好,我是小花,我今年21歲了
大家好,我是小花,我今年22歲了

 

特性

在新版的python3中,提供了property函式,可以關聯到存取方法,實際上它是一個類,只不過我們用起來是函式的用法。

class Person():
    def __init__(self,name,age):
        self.__name = name
        self.__age = age

    def info(self):
        print(f'大家好,我是{self.__name},我今年{self.__age}歲了')

    def get_age(self):
        print(f'這是類裡面-我正在讀取age的值:{self.__age}')
        return self.__age

    def set_age(self,age):
        print(f'這是類裡面-我正在設定age的值:{age}')
        self.__age = age

    def del_age(self):
        print(f'這是類裡面-我正在刪除age:{self.__age}')
        del self.__age

    age = property(get_age,set_age,del_age)

xiaohua = Person('小花',21)
xiaohua.info()
xiaohua.age = 18
xiaohua.info()
print(f'我在外面讀取age的值:{xiaohua.age}')
del xiaohua.age

列印結果:

大家好,我是小花,我今年21歲了
這是類裡面-我正在設定age的值:18
大家好,我是小花,我今年18歲了
這是類裡面-我正在讀取age的值:18
我在外面讀取age的值:18
這是類裡面-我正在刪除age:18

 

示例中property傳入了三個引數,順序分別是讀取方法,設定方法,刪除方法,如果都不傳,那麼該特性將不可讀也不可寫,傳了哪個方法就擁有哪個功能,有第四個可選引數,傳入一個文件字串。

 

property也可以當成裝飾器用

class Person():
    def __init__(self,name,age):
        self.__name = name
        self.__age = age

    def info(self):
        print(f'大家好,我是{self.__name},我今年{self.__age}歲了')

    @property
    def age(self):
        print(f'這是類裡面-我正在讀取age的值:{self.__age}')
        return self.__age

    @age.setter
    def age(self,age):
        print(f'這是類裡面-我正在設定age的值:{age}')
        self.__age = age

xiaohua = Person('小花',21)
xiaohua.info()
xiaohua.age = 18
xiaohua.info()
print(f'我在外面讀取age的值:{xiaohua.age}')

列印結果:

大家好,我是小花,我今年21歲了
這是類裡面-我正在設定age的值:18
大家好,我是小花,我今年18歲了
這是類裡面-我正在讀取age的值:18
我在外面讀取age的值:18

 

繼承

常規繼承

繼承的寫法是在類定義的時候類名後面的括號裡傳入父類名稱

class Person():
    def info(self):
        print('人類正在統治世界')

class student(Person):
    def __init__(self):
        print('我是一名小學生')

p = student()
p.info()

列印結果:

我是一名小學生
人類正在統治世界

 

訪問父類方法

在python中訪問父類方法用一個特殊的函式 : super()

class Person():
    def info(self):
        print('人類正在統治世界')

class student(Person):
    def __init__(self):
        super().info()
        print('我是一名小學生')

p = student()

列印結果:

人類正在統治世界
我是一名小學生

 

如果是初始化類的時候要呼叫父類的建構函式,也是一樣的呼叫方式:

class Person():
    def __init__(self,name):
        self.__name = name

    def info(self):
        print(f'人類正在統治世界:{self.__name}')

class student(Person):
    def __init__(self,name):
        super().__init__(name)

p = student('阿西吧')
p.info()

列印結果:

人類正在統治世界:阿西吧

 

方法重寫

子類將父類的方法進行重寫覆蓋

class Person():
    def info(self):
        print('人類正在統治世界')

class student(Person):
    def info(self):
        print('小學生正在統治世界')

p = student()
p.info()

列印結果:

小學生正在統治世界

 

多重繼承

多重繼承雖然很強大,也很容易成為車禍現場,多個父類中如果有建構函式如果有同名方法都將搞得你頭暈腦脹,正常情況下,應該避免使用多重繼承,除非忍不住。。。

class Person():
    def info(self):
        print('人類正在統治世界')

class Young():
    def young_info(self):
        print('年輕人太天真')

class student(Person,Young):
    def __init__(self):
        print('小學生正在統治世界')

p = student()
p.info()
p.young_info()

列印結果:

小學生正在統治世界
人類正在統治世界
年輕人太天真

 

型別校驗

class Person():
    def info(self):
        print('人類正在統治世界')

class Young():
    def young_info(self):
        print('年輕人太天真')

class student(Person,Young):
    def __init__(self):
        print('小學生正在統治世界')


a = issubclass(student,Person)
print(f'是不是子類:{a}')

x = student.__bases__
print(f'父類是:{x}')

s = student()
z = isinstance(s,student)
print(f'是不是例項:{z}')

列印結果:

是不是子類:True
父類是:(<class '__main__.Person'>, <class '__main__.Young'>)
小學生正在統治世界
是不是例項:True

 

是不是例項判斷  如果和父類進行判斷也算是例項。

 

抽象介面

面向介面程式設計的時候都是先定義介面,然後子類去實現介面實現方法,在python3中引入了abc模組,可以幫助我們定義抽象介面

import abc

class Person(metaclass=abc.ABCMeta):

    @abc.abstractmethod
    def eat(self):
        pass


class student(Person):

    def eat(self):
        print('小學生也可以吃飯')


x = student()
x.eat()

列印結果:

小學生也可以吃飯

 

抽象類中定義的介面在子類中必須實現

 

靜態方法

class student():

    remark = '我是祖國的花朵'

    @classmethod
    def sing(cls):
        print('小學生也可以唱歌 ' + cls.remark)

    @staticmethod
    def eat():
        print('小學生也可以吃飯')

student.eat()
student.sing()

列印結果:

小學生也可以吃飯
小學生也可以唱歌 我是祖國的花朵

 

兩種裝飾器可以定義靜態方法,注意區別,@classmethod裝飾的方法有預設引數cls,表示當前類,可以取到屬性。

 

相關文章