面向對象基本特征
封裝
封裝是指對外界隐藏資訊,不能随意通路、修改對象的資料和方法
封裝是通過限制類的屬性和方法的通路方式來實作的封裝效果
封裝的三個層次:
類的封裝:外部可以任意通路、修改類中的屬性和方法
私有屬性:外部不可以通路、修改勒種的屬性和方法
公有方法+私有屬性:外部有條件限制的通路、修改屬性,調用方法
封裝表現1:
類的定義:将某些特定屬性和方法進行“隔離”
每個學生有自己的年齡,外部可以任意讀取或者修改
class Student:
def __init__(self,name,age):
self.name = name
self.age = age
s1 = Student("李白",18)
s2 = Student("杜甫",20)
s2.age = 200
print(s1.name)
print(s2.age)
封裝表現2:
屬性私有:隻能在類的内部使用,外部不能使用
不讓外部讀取、修改學生的年齡
class Student:
def __init__(self,name,age):
self.name = name
self.__age = age#使用兩個下劃線開頭的屬性,定義為私有屬性
print(self.__age)
__secret = True
s1 = Student("李白",18)
# print(s1.__age)#外界無法直接通過屬性名稱來通路
#雖然文法可以在外部通過_Student__age通路到私有屬性,但是不推薦使用
print(s1._Student__age)
#__dict__檢視目前對象或者類有哪些屬性
print(s1.__dict__)
print(Student.__dict__)
封裝表現3:
私有屬性+ 公有方法:有限制條件的開放給外部
可以讀取年齡,但不能随意修改年齡
設定年齡必須在(1,125)之間
class Student:
def __init__(self,name,age):
self.name = name
self.__age = age
def getAge(self):
return self.__age
def setAge(self,age):
if 0 < age < 125:
self.__age = age
else:
print("年齡不符合人類")
s1 = Student("李白",18)
print(s1.getAge())
s1.setAge(200)
print(s1.getAge())
私有方法
可以在類的内部使用,有條件的開放給外部
class Person:
def __tellSercert__(self):
print("夏天夏天悄悄過去,留下小秘密~~~~")
def talk(self,object):
if object == "好基友":
self.__tellSercert__()
else:
print("我是一個木得感情木得秘密的人")
ming = Person()
ming.talk("好基友")
ming.talk("隔壁小黑")
封裝的簡化寫法
裝飾器
property裝飾器:把一個方法僞裝成一個屬性,在調用這個方法的時候不需要加()就可以直接得到傳回值
class Dog:
@property#裝飾器
def bark(self):
print("旺旺旺~~~")
return 89757
d = Dog()
num = d.bark #注意這裡沒有括号呦
print(num)
總結
使用@property裝飾器時,方法名不必與屬性名相同
可以更好的防止外部通過猜測私有屬性名稱來通路
凡是指派語句就會觸發set方法,擷取屬性值會觸發get方法
繼承
面臨的問題:
相似類型的定義會産生大量重複的代碼
類的定義沒有很好的擴充性‘
解決的方法:
定義類和類之間的關系,子類擁有父類的全部屬性和方法,并可以為之擴充
示例
class Pet:
def __init__(self,name,age):
self.name = name
self.age = age
print(f"一隻名字叫{self.name}的寵物出生了")
def eat(self):
print(f"{self.name}在吃東西~~~")
def run(self):
print(f"{self.name}在溜達~~~")
class Dog(Pet):
pass
class Cat(Pet):
pass
d = Dog("咯咯",3)
d.run()
c = Cat("布丁",1)
c.eat()
1.繼承的概念:
Dog和Cat繼承了Pet類
Dog和Cat稱為Pet的子類、派生類
Pet稱為Dog和Cat的父類、超類、基類
子類預設擁有父類公有的屬性和方法的定義
2.子類調用方法的順序
調用方法時,子類中有的,調用子類中的
子類中沒有的,調用父類的
一旦在子類中找到,就不在去父類中查找了
子類不能繼承父類的私有屬性或者方法
class Father:
__secret = "小秘密"
story = "從前有座山,山上有座廟"
def tellStory(self):
print(self.story)
def __tellSecret(self):
print(self.__secret)
class Son(Father):
def tell(self):
# self.tellStory()
self.__tellSecret()
s = Son()
s.tell()
3.重寫/覆寫
子類和父類擁有相同名稱的方法
可以了解為子類對于父類行為的擴充和補充
class Pet:
master = True
def __init__(self,name,age):
self.name = name
self.age = age
print(f"一隻名字叫{self.name}的寵物出生了")
def eat(self):
print(f"{self.name}在吃東西~~~")
def run(self):
print(f"{self.name}在溜達~~~")
class Dog(Pet):
#重寫父類方法
def eat(self):
print(f"{self.name}在啃骨頭")
#擴充,定義子類特有功能
def lookAfter(self):
print(f"{self.name}在看門,汪汪汪!")
d = Dog("旺财",2)
d.eat()
d.lookAfter()
4.子類可以在類定義時,可以使用super()調用父類的方法
應用1:和重寫不同,重寫是對父類方法的完全覆寫,這是對父類方法的補充
class Pet:
def __init__(self,name,age):
self.name = name
self.age = age
print(f"一隻名字叫{self.name}的寵物出生了")
def eat(self):
print(f"{self.name}在吃東西~~~")
def run(self):
print(f"{self.name}在溜達~~~")
class Cat(Pet):
def eat(self):
print(f"{self.name}伸了個懶腰")
super().eat()
print(f"{self.name}吃完東西後,舔了舔爪子")
c = Cat("布丁",2)
c.eat()
應用2:對象初始化時,簡化重複屬性的指派
class Cat(Pet):
def __init__(self,name,age,sex):
# self.name = name
# print(f"一隻名叫{self.name}的寵物出生了")
super().__init__(name)#代替了上兩句代碼,簡化了重複屬性的指派
self.age = age
self.sex = sex
5.多繼承
子類可以有多個父類
例如:狗是脊椎動物,哺乳動物,寵物。。。
class Father:
caihua = "有才"
class Mother:
yanzhi = "有貌"
class Child(Father,Mother):
pass
c = Child()
print(c.caihua,c.yanzhi)
print(Child.__bases__)#可以通過類名.__bases__檢視其父類
6.通路子類的屬性或者方法時,解析的路徑(順序)
class Father:
def getMoney(self):
print("爸爸給了零花錢")
class Mother:
def getMoney(self):
print("媽媽給了零花錢")
class Child(Father,Mother):
def getMoney(self):
super().getMoney()
#按照繼承的順序查找父類中的方法,是以先找Father類
print("孩子獲得了零花錢")
c = Child()
c.getMoney()
從第一個父類開始向上查找,直到查找結束都沒有,再對第二個父類進行查找
深度優先:Child -> Father -> GrandFather -> Mother
class GrandFather:
pass
# def getMoney(self):
# print("爺爺給了零花錢")
class Father(GrandFather):
pass
# def getMoney(self):
# print("爸爸給了零花錢")
class Mother:
def getMoney(self):
print("媽媽給了零花錢")
class Child(Father,Mother):
def getMoney(self):
super().getMoney()
#按照繼承的順序查找父類中的方法,是以先找Father類
print("孩子獲得了零花錢")
c = Child()
c.getMoney()
print(Child.mro())#可以通過類名.mro()的方式來檢視類的解析順序
object是所有類的父類
“萬事萬物”皆為對象,因為所有的類都預設繼承object
7.菱形繼承
廣度優先:Child -> Father -> Mother -> Human
多态
想要解決的問題
讓程式能夠有更強的靈活性
讓程式能夠有更好的适應性
概念:一個類的多種形态
情況1:通過繼承和重寫來實作
class Animal:
def eating(self):
print("動物在吃東西")
class Pet(Animal):
def eating(self):
print("寵物在吃東西")
class Dog(Pet):
def eating(self):
print("狗在啃骨頭~")
class Cat(Pet):
def eating(self):
print("小貓在吃魚")
class Zoo:
def animalEating(self,animal):
animal.eating()
z = Zoo()
a = Animal()
p = Pet()
d = Dog()
c = Cat()
#Dog和Cat都作為Animal的不同形态
#都可以直接調用animal所具有的屬性和方法
z.animalEating(a)
z.animalEating(p)
z.animalEating(d)
z.animalEating(c)
情況2:Python持有
沒有繼承關系,但是也具備相同的特征、方法,也可以直接使用
class venusFlytrap:#捕蠅草
def eating(self):
print("捕蠅草在吃小蟲子")
v = venusFlytrap()
z.animalEating(v)
捕蠅草不繼承于Animal類,但是具有和它相同的特征,在python隻要具有相同的特征和方法,沒有繼承關系也可以直接使用
type和isinstance
#type判斷類型時,隻看直接類型
print(type(c) is Cat)#True
print(type(c) is Animal)#False
print(type(c) is Pet)#False
#isinstance 判斷對象是否為一個類型的執行個體
#判斷執行個體類型時,涵蓋父類的類型
print(isinstance(c,Cat))#True
print(isinstance(c,Pet))#True
print(isinstance(c,Animal))#True
print(isinstance(venusFlytrap,Animal))#False