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()
列印結果:
大家好,我是小花,我今年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,表示當前類,可以取到屬性。
&n