面向物件,特性之繼承
1,什麼是繼承?
-
繼承指的是一種關係,必須存在兩個物件才能產生這種關係
-
被繼承的稱為父,繼承的一方稱為子
-
在程式中,繼承指的是類與類之間的關係
2,為什麼要使用繼承?
繼承可以擴充套件已存在的程式碼模組(類)
在程式中,通過繼承可以直接使用父類已有的程式碼
3,怎麼使用繼承
繼承類的語法
class Father:
pass
class Som(Father): #子類後面加上括號,寫上父類的名稱
pass
在python中,一個字類可以有多個父類,多個父類在括號中用逗號隔開
繼承父類中物件和方法的語法
class Parent:
year = 2018
def coding(self):
print('coding')
class Sub(Parent):
pass
print(Sub.year)
s1 = Sub()
s1.coding()
4,繼承對程式設計的作用
假設有個學生管理需求:
class Student:
def __init__(self,name,age,sex):
self.name = name
self.age = age
self.sex = sex
def study(self):
print('正在學習中')
def eat(self):
print('正在吃飯中')
學生的屬性和技能也適用於老師,此時可以引用繼承,減少程式碼的冗餘
class Teacher(Student):
pass
t1 = Teacher('alex',30,'man')
t1.eat()
t1.study()
從邏輯上來說,如果學生有打遊戲的技能,而老師並沒有這個需求,因此繼承到了老師並不需要的技能
正確姿勢: 抽取公共的父類 (抽象)
抽象 : 抽取多個類中相同得部分,形成另一個類
把學生和老師共有的內容抽到另一個類中,學生和老師分別繼承這個類,這樣就避免了一個類繼承到不需要的內容 因此應該先抽象,再繼承
小結:
-
通過繼承,避免了重複程式碼的編寫。
-
繼承的作用是可以直接使用父類已有的程式碼
-
通過抽象,避免了一個類繼承到不需要的內容
-
抽象的作用是儲存多個子類相同的屬性和技能
-
正確地順序應該先抽象,再繼承
1,派生
class Person:
• def __init__(self,name,age,sex):
• self.name = name
• self.age = age
• self.sex = sex
• def sayhi(self):
• print('hello,')
class Student(Person): # 學生屬於人類,可以直接繼承
• def __init__(self,number): # 加上一些學生特有的屬性
• self.number = number
• def study(self):
• print('%s正在學習'%self.name)
-
派生指某個子類繼承父類,並且擁有自己獨特的屬性或技能
-
該子類稱之為派生類
-
只要子類中出現任何新內容,這就是一個派生類
2,覆蓋
class A:
age = 18#age相同
def f1(self):#f1相同
print(" A f1" )
pass
class B(A):
age1 = 19
def f1(self):#f1
self.f1()
print(" B f1")
b1 = B()
print(b1.age)
b1.f1()
小結:
-
子類出現了與父類重複的名字 稱之為覆蓋
-
方法1 從父類去調
class Person:
def __init__(self,name,age,sex):
self.name = name
self.age = age
self.sex = sex
def sayhi(self):
print('hello,')
class Student(Person): # 學生屬於人類,可以直接繼承
def __init__(self,name,age,sex,number): # 加上一些學生特有的屬性
#self.name = name
#self.age = age
#self.sex = sex #程式碼重複
Person.__init__(self,name,age,sex) #在子類訪問父類的方式1
self.number = number
def study(self):
print('%s正在學習'%self.name)
stu1 = Student('成龍',20,'man',4235)
print(stu1.__dict__)
方法2 super()函式
class Person:
def __init__(self,name,age,sex):
self.name = name
self.age = age
self.sex = sex
def sayhi(self):
print('hello,')
class Student(Person): # 學生屬於人類,可以直接繼承
def __init__(self,name,age,sex,number): # 加上一些學生特有的屬性
super(Student,self).__init__(name,age,sex) #super()表示特殊的物件
super().__init__(name,age,sex)#效果一樣,這是py3的語法
self.number = number
def study_1(self):
super().sayhi() #訪問父類的方法1
Person.sayhi(self) #訪問父類的方法2
print('%s正在學習'%self.name)
stu1 = Student('成龍',20,'man',4235)
stu1.study_1()
print(stu1.__dict__)
瞭解,在python2中,super的用法不同。super(Student,self).init()
1,存在一個父類的情況
class A:
age = 10
class B(A):
age = 11
class C(B):
age = 12
c1 = C()
c1.age = 13
print(c1.age)
沿著繼承關係找,無論是屬性還是方法! 如果沒有則報錯!
2,存在多個父類的查詢順序
(1) ,繼承的父類,沒有父類,按照繼承順序,從左往右依次查詢
class A:
a = 0
pass
class B:
a = 1
pass
class C:
a = 2
pass
class D(A,B,C):
a = 3
pass
d = D()
d.a = 4
print(d.a)
查詢順序為 : A -- B -- C -- D
(2),深度優先,沿著一條線找到底
繼承的父類,存在父類,則先把父類找完 這種查詢方式僅僅在非菱形繼承(沒有共同父類)的情況下
class Q:
a = 10
class A(Q):
a = 0
pass
class W:
a = 11
class B(W):
a = 1
pass
class C:
a = 2
pass
class D(A,B,C):
a = 3
pass
d = D()
d.a = 4
print(d.a)
查詢順序為E -- A -- F -- B --同理
3,廣度優先,並非絕對的廣度優先,而是基於深度的廣度優先。
先是深度優先,如果發現有共同父類,則返回。最後再查詢共同父類 該查詢順序是通過C3演算法得來
瞭解:
新式類和經典類
主要針對 python2 和 python3 區分的
所有直接繼承或間接繼承object的類 都是新式類
object 稱之為根類 意思是 所有類 都源自於object類
為什麼這麼設計?
-
例如:建立物件時,需要申請記憶體空間,建立新的名稱空間,將物件的屬性放入名稱空間, 這一些了複雜的基礎操作,都yo由object來完成 簡單地說object提供了一些常用的基礎操作
-
即所有類都屬於新式類(在python3中)
在python3中預設所有類都是新式類
class S:
pass
class Student(S):
pass
bases__用於檢視父類
print(Student.__bases__)
顯示屬性的查詢順序列表,屬性查詢屬性就是按照該列表來查詢的
print(Student.mro())
mro
檢視訪問路徑
"super訪問父類內容時 按照mro列表屬性查詢"
class S:
def f1(self):
print("s f1")
class A(S):
pass
class B(S):
def f1(self):
print("b f1")
pass
class C(A,B):
def f2(self):
print("c f2")
super().f1()
print(C.mro())
c1 = C()
c1.f2()
1,什麼是組合
-
多個物件放在一起就是組合
-
一個物件將另一個物件作為自己的屬性,就是組合
2,組合的目的
-
處理資料更有效率,有效降低耦合度和程式碼的冗餘
3,組合的實現
-
程式碼1 是通過繼承實現程式碼的精簡
-
-
手機的屬性有品牌,價格,運營商,號碼
-
如果全部都放到程式碼1 的父類中,看起來非常的臃腫,管理成本非常高,擴充套件性變得很差
-
我們可以通過組合實現程式碼的管理,使程式碼的可讀性和整潔性都得到有效提高
-
程式碼2 是新增手機功能後通過繼承和組合一起實現.
-
組合其實我們在使用者互動的練習就實現過了
程式碼1,繼承
class Person:
def __init__(self, name, sex, age, number):
self.name = name
self.sex = sex
self.age = age
self.number = number
class Student(Person):
def __init__(self,name,sex,age,number,game):
super().__init__(name,sex,age,number)
self.game = game
def show_info(self):
print(self.__dict__)
def select(self):
print('%s正在選課'%self.name)
class Teacher(Person):
def __init__(self,name,sex,age,number,teach_class):
super().__init__(name,sex,age,number)
self.teach_class = teach_class
def show_info(self):
print(self.__dict__)
def set_score(self):
print('%s正在為學生打分'%self.name)
s1 = Student('韓信','man',18,51,'王者榮耀')
s1.show_info()
t1 = Teacher('韓信','man',18,51,'王者榮耀')
t1.show_info()
程式碼2 ,組合的形式
class Phone:#組合的程式碼
def __init__(self,phonenumber,operator,address):
self.phonenumber = phonenumber
self.operator = operator
self.address = address
def call(self,t):
print("%s 正在撥號 %s" % (t.name,self.phonenumber))
class Person:#父類
def __init__(self,name,sex,age):
self.name = name
self.sex = sex
self.age = age
class Student(Person):#子類
def __init__(self,name,sex,age,number):
super().__init__(name, sex, age)
self.number = number
def show_info(self):
print(self.__dict__)
def select_cursor(self):
print("%s 正在選課...." % self.name)
class Teacher(Person):#子類
def __init__(self,name,sex,age,salary,level):
super().__init__(name,sex,age)
self.salary = salary
self.level = level
def set_score(self):
print("%s 正在為學生打分..." % self.name)
stu = Student("喬峰","男",38,"007")
p1 = Phone("1999999999","中國小米移動","上海浦東")
stu.q = p1 #這裡的q是變數名,相當於把p1賦值給q,通過stu來呼叫
stu.q.call(stu) #不能直接stu.p1.call()