上次我們說到,關於python面向對象
面向對象是什麼
面向對象和麪向過程的區別
類和對象
python中如何定義類和實例化對象
類的屬性和方法
這裏我們講面向對象的特徵:封裝,繼承,多態,三大特徵。
也有說抽象加在一起算作是四大特徵,這一觀點並未得到公認。
封裝
什麼是封裝?
廣義的封裝:將事物的細節進行封起,提供好用的方法供使用者使用。
面向對象的封裝:
1.將類的屬性和方法封裝成一個或者多個類,使用的時候調用對象的屬性和方法。
2.將類的屬性進行封裝(私有化private),僅供類內部進行訪問,提供公開的方法(getter和setter)進行訪問。
python中如何實現封裝
對於上面的第二點,纔是面向對象封裝特性的重點。
請看下面這段代碼:
# -*- coding: utf-8 -*-
class Richman:
def __init__(self):
self.money = 1000000
self.company = "alibaba"
def speak(self):
print("我對錢沒有興趣!")
print("一個月一塊錢的工資!")
if __name__ == "__main__":
rich1 = Richman()
print(rich1.money)
rich1.money = 1000
print(rich1.moneyA)
運行結果如下,可以看到可以直接訪問對象的屬性和修改屬性,這樣是極爲不好的,不符合封裝的特性。
如何修改呢,將屬性進行私有化。
class Richman:
def __init__(self):
self.__money = 1000000
self.__company = "alibaba"#__屬性即是私有屬性。
def speak(self):
print("我對錢沒有興趣!")
print("一個月一塊錢的工資!")
if __name__ == "__main__":
rich1 = Richman()
print(rich1.money)
rich1.money = 1000
print(rich1.moneyA)
修改爲私有屬性,則無法進行訪問,如要進行訪問則需要對外界提供公開的方法。
同理,屬性可以私有,方法同樣可以私有。
三種封裝訪問方式
上面說到封裝特性的時候,採用getter,和setter進行提供公開的訪問
1.getter和setter
class people:
def __init__(self,name,age,gender):
self.__name = name
self.__age = age
self.__gender = gender
def __str__(self):
return "name = "+ self.__name +",age = "+ self.__age
def get_name(self):
return self.__name
def set_name(self,name):
self.__name = name
def get_age(self):
return self.__age
def set_age(self,age):
self.__age = age
if __name__ == "__main__":
p1 = people("xuhaobo","18","男")
print(p1.get_name())
print(p1.get_age())
print(p1)
p1.set_name("wangwang")
p1.set_age("20")
print(p1)
提供了getter和setter可以對私有屬性進行訪問和修改。
2.將訪問方法再進行封裝,讓用戶感覺沒有變化。
使用property方法
如下的:將之間的方法再提供給用戶。用戶使用起來沒有變化,get在前,set在後
name = property(get_name,set_name)
age = property(get_age,set_age)
class people:
def __init__(self,name,age,gender):
self.__name = name
self.__age = age
self.__gender = gender
def __str__(self):
return "name = "+ self.__name +",age = "+ self.__age
def get_name(self):
return self.__name
def set_name(self,name):
self.__name = name
def get_age(self):
return self.__age
def set_age(self,age):
self.__age = age
name = property(get_name,set_name)
age = property(get_age,set_age)
if __name__ == "__main__":
p1 = people("xuhaobo","18","男")
print(p1.name)
print(p1.age)
print(p1)
p1.name = "wangwang"
p1.age = "20"
print(p1)
可以看到用戶訪問起來並沒有覺得有任何不同。
3.使用property裝飾器
可以說是property(get,set)的變式寫法
將property()寫爲如下形式:
@property #裝飾器
def gender(self):
return self.__gender
@gender.setter #一般使用私有屬性的名稱作爲@的值
def gender(self,gender):
self.__gender = gender
代碼如下:
class people:
def __init__(self,name,age,gender):
self.__name = name
self.__age = age
self.__gender = gender
def __str__(self):
return "name = "+ self.__name +",age = "+ self.__age
def get_name(self):
return self.__name
def set_name(self,name):
self.__name = name
def get_age(self):
return self.__age
def set_age(self,age):
self.__age = age
#property(get,set)的變式寫法
@property
def gender(self):
return self.__gender
@gender.setter
def gender(self,gender):
self.__gender = gender
name = property(get_name,set_name)
age = property(get_age,set_age)
if __name__ == "__main__":
p1 = people("xuhaobo","18","男")
print(p1.name)
print(p1.age)
print(p1)
p1.name = "wangwang"
p1.age = "20"
print(p1)
print(p1.gender)
p1.gender = "女"
print(p1.gender)
print(p1)
故在定義類之時,一定要進行對類進行封裝,私有化其屬性,再提供公開的get和set進行訪問。具有一定安全性。
繼承
繼承是什麼?下一代獲得上一代遺留的東西的過程稱爲繼承。
在python之中,一個類如何繼承另一個類呢,我通過代碼進行演示。
class Richman:
def __init__(self):
self.money = 1000000
self.mompany = "alibaba"
def speak(self):
print("我對錢沒有興趣!")
print("一個月一塊錢的工資!")
class Son(Richman):
pass
if __name__ == "__main__":
s1 = Son()
print(s1.money)
s1.money = 1000
print(s1.money)
s1.speak()
可以看到,son類中什麼內容也沒有寫,是繼承了richman中的屬性和方法。
下面我將money屬性改爲私有,可以看到報錯。
self.__money = 1000000
是因爲繼承只能繼承公開的屬性和方法,私有屬性和方法無法繼承
重寫override
如果對繼承的方法不滿意怎麼辦,不合適,那麼就需要對方法進行重寫。
class Richman:
def __init__(self):
self.__money = 1000000
self.mompany = "alibaba"
def speak(self):
print("我對錢沒有興趣!")
print("一個月一塊錢的工資!")
def working(self):
print("A你是個好同志,做事我放心!")
print("B你是個lowB,幹事不好!")
class Son(Richman):
def working(self):
print("還是自己人來好一點!,我把自己兄弟叫來")
if __name__ == "__main__":
s1 = Son()
r1 = Richman()
s1.speak()
r1.speak()
s1.working()
r1.working()
對父類的working方法進行了重寫,可以看到重寫後則就是調用的是重寫後在該類中的working,父類和子類中的方法,調用時是就近原則。
一道常見的面試題:
Python中有函數重載和方法重寫嗎?
答案:沒有函數重載,有方法重寫。
why:
overload:名稱相同,參數不同或者類型不同的一些函數。
1.由於python是弱數據類型語言,則類型不會不相同,
2.由於py是解釋型語言,執行時候後者所謂重載的函數會覆蓋之前的函數,則沒有重載。
重寫就不用說了,上面演示的就是重寫
繼承的作用和目的是爲了:代碼複用和多態。代碼複用是繼承的本質。
super關鍵字和多繼承
同樣是面向對象,java不支持多繼承。
py如何支持多繼承的呢?
如 class Son(Richman,xxx,xxxx,…)一個類可以有多個父類。
這有一個問題:同時繼承多個類,類中都用同一個方法,該如何調用呢?
在py3中現在使用的是新式類,採用廣度優先,即繼承的順序來調用。
在舊式類中,採用的是深度優先,按照繼承的類的深度來調用,如果深度想同,則再按照繼承順序。
super ,超級的意思,----》算是個指針,指向父類。
在子類中使用。
super().方法名()
使用如下:
# -*- coding: utf-8 -*-
class Richman:
def __init__(self):
self.__money = 1000000
self.mompany = "alibaba"
def speak(self):
print("我對錢沒有興趣!")
print("一個月一塊錢的工資!")
def working(self):
print("A你是個好同志,做事我放心!")
print("B你是個lowB,幹事不好!")
class Son(Richman):
def working(self):
print("還是自己人來好一點!,我把自己兄弟叫來")
def test(self):
super().working()
if __name__ == "__main__":
s1 = Son()
r1 = Richman()
s1.speak()
r1.speak()
s1.working()
r1.working()
s1.test()
結果:
在初始化函數的時候,是對子類操作,不像其他語言。如下:
class RichMan:
def __init__(self):
print("這是父類!")
class Son(RichMan):
def __init__(self):
print("這是子類!")
if __name__ == "__main__":
s1 = Son()
代碼執行:
如果需要調用父類,則需要使用super。
class RichMan:
def __init__(self):
print("這是父類!")
class Son(RichMan):
def __init__(self):
super().__init__()
print("這是子類!")
if __name__ == "__main__":
s1 = Son()
super()調用的方法中是有參則傳參。
多態
何爲多態?
對象的多種狀態。
在繼承的基礎上,父類引用指向子類實例的現象,稱爲多態。
比如java中父類list,一個子類arraylist。
List ls = new ArrayList()
父類調用子類方法,而py是弱數據類型,上面例子成爲:
ls = ArrayList()
由於py是弱數據類型,天生就是支持多態的,則其不關心多態的問題。
這裏就不多講了。
今天的分享就到這裏了,喜歡的小夥伴可以點贊和關注呀!博主持續分享。