【一】繼承介紹
# 面向對線三大特性:繼承 封裝 多型
# 繼承
# 【一】什麼是繼承
# 繼承就是一種建立新類的方式,新建的類可以繼承一個或多個類的屬性。
# 新的類如果有自己的屬性,那就叫派生
# 【二】繼承的優點
# 可以繼承父類的所有屬性和方法,實現程式碼的去重
# 【三】繼承方式
# 單繼承:繼承一個父類的子類
# 多繼承:繼承多個父類的子類
# class Student(School):
# 繼承的類叫父類 School
# 新建的類叫子類 Student
class Person(object):
height = 180
weight = 50
class School(object):
school = "清華"
# 【1】單繼承:只繼承一個父類
class Student(Person):
def __init__(self, name):
self.name = name
def tell_me(self):
print(f"我是 {self.name} 我身高 {self.height} 體重 {self.weight}")
stu1 = Student("dream")
stu1.tell_me()
# 【2】多繼承:繼承兩個以上的父類
class Teacher(School, Person):
def __init__(self, name):
self.name = name
def tell_me(self):
print(f"我是 {self.name} 我身高 {self.height} 體重 {self.weight} 學校在 {self.school}")
teacher = Teacher("opp")
teacher.tell_me()
# 【3】如何檢視繼承的父類
# (1)檢視當前繼承的父類 __base__ : 如果繼承多個父類,預設只列印第一個繼承的父類
print(Student.__base__) # <class '__main__.Person'>
print(Teacher.__base__) # <class '__main__.Person'>
# (2)檢視當前繼承的父類們 : __bases__ 一個元組,元組中放的是所有繼承的父類
print(Student.__bases__) # (<class '__main__.Person'>,)
print(Teacher.__bases__) # (<class '__main__.Person'>, <class '__main__.School'>)
【二】經典類和新式類
# 經典類和新式類的區別在於Python版本的不同
# 在 py3 版本之前存在兩個概念 ,在之後就沒有經典類的概念了,只有新式類
# 【一】什麼是經典類
# 在py2中沒有顯示繼承 object 的類或者是該類的子類都是經典類
# 【二】什麼是新式類
# 在py2中顯示繼承 object 的類或者是該類的子類都是新式類
# 在py3之後所有的類預設都是新式類,不寫m預設繼承 object
【三】繼承和抽象
# 什麼是繼承和抽象
# 繼承是子類和父類之間的關係,什麼是什麼的概念
# 抽象相當於將某部分抽立起來再總結
# 【一】抽象
# 將不同的類。根據指定的表徵總結起來歸介於一個類
# 貓和狗 --> 動物
# 豬八戒 麥兜 ---> 豬
# 梅西 奧巴馬 --> 人
# 豬 和 人 ---> 動物
# 【二】繼承
# 基於抽象的結果,然後用語言去實現
# 【三】繼承和抽象
# 繼承是由少變多
# 抽象是由多變少
# 【四】在python中實現繼承
# 【1】沒有繼承和抽象
# 有一隻貓
class Cat(object):
def speak(self):
print(f"貓可以喵喵叫")
def eat(self):
print("貓可以吃飯")
def drink(self):
print("貓可以喝水")
# 有一隻狗
class Dog(object):
def speak(self):
print(f"狗可以旺旺叫")
def eat(self):
print("狗可以吃飯")
def drink(self):
print("狗可以喝水")
# 【2】抽象
# 總結起來一個公共的類,可以吃喝拉撒睡
class Animal(object):
def speak(self):
print(f"{self.name}可以叫")
def eat(self):
print(f"{self.name}可以吃飯")
def drink(self):
print(f"{self.name}可以喝水")
# 【3】繼承
# 有一隻貓
class Cat(Animal):
def __init__(self, name):
self.name = '貓'+name
# 有一隻狗
class Dog(Animal):
def __init__(self, name):
self.name = '狗'+name
cat_one = Cat(name='小花')
print(cat_one.speak())
dog_one = Dog(name="旺財")
print(dog_one.speak())
【四】封裝後繼承的屬性查詢順序
【1】封裝之前的屬性查詢順序
class Foo:
def f1(self):
print('Foo.f1')
# 【四】在父類 Foo 裡面找到了 f2
def f2(self):
# 【五】列印 Foo.f2
print('Foo.f2')
# 【六】self.f1 ---> self 是誰 ?
# 觸發的是 Foo.f1 還是 Bar.f1?
# Foo.f1 3
# Bar.f1 2
self.f1()
class Bar(Foo):
# 【七】因為是 透過Bar例項化得到的物件,所以 self 就是 Bar
def f1(self):
# 【八】列印 Bar.f1
print('Bar.f1')
# 【三】Bar裡面沒有f2,去父類找 Foo
# 【一】類例項化得到物件
b = Bar()
# 【二】物件呼叫方法 f2
b.f2()
class B(object):
def read(self):
print(self)
class A(B):
...
a = A()
a.read()
b = B()
b.read()
# 哪個物件呼叫方法,self 就是誰
【2】有封裝的時候的繼承
class Foo:
# __f1 --> _Foo__f1
def __f1(self):
print('Foo.f1')
# 【4】在Foo裡面找到了 f2
def f2(self):
# 【5】列印 Foo.f2
print('Foo.f2')
# 【6】
# 沒有變形的時候 self 是誰就去誰裡面找
# 但是變形之後 就只能在自己的類裡面找,沒辦跳到別的類裡面
# Foo.f1 2
# Bar.f1 3
self.__f1()
class Bar(Foo):
# 【3】沒有f2. 去 Foo
def __f1(self):
print('Bar.f1')
# 【1】
b = Bar()
# 【2】
b.f2()
【3】總結
# 如果屬性不封裝的情況下,誰例項化得到的self 就去誰裡面找
# 如果屬性封裝的情況下 , 誰例項化得到的self 無效,只能在當前所在的類的民稱空間裡面找
【五】派生
# 派生是指,子類繼承父類,派生出自己的屬性與方法,並且重用父類的屬性與方法
【1】子類繼承父類的屬性
class People:
school = '清華大學'
def __init__(self, name, sex, age):
self.name = name
self.sex = sex
self.age = age
class Teacher(People):
# 派生 : 派生出自己新的屬性,在進行屬性查詢時,子類中的屬性名會優先於父類被查詢
def __init__(self, name, sex, age, title):
self.name = name
self.sex = sex
self.age = age
self.title = title
def teach(self):
print('%s is teaching' % self.name)
# 只會找自己類中的__init__,並不會自動呼叫父類的
obj = Teacher('dream', 'male', 18, '高階講師')
print(obj.name, obj.sex, obj.age, obj.title)
# dream male 18 高階講師
【2】繼承方式一
class People:
school = '清華大學'
def __init__(self, name, sex, age):
self.name = name
self.sex = sex
self.age = age
class Teacher(People):
# 派生 : 派生出自己新的屬性,在進行屬性查詢時,子類中的屬性名會優先於父類被查詢
def __init__(self, name, sex, age, title):
# 直接呼叫 父類 中 的 __init__ 方法
# 呼叫的是函式,因而需要傳入self
People.__init__(self, name, age, sex)
self.title = title
def teach(self):
print('%s is teaching' % self.name)
# 只會找自己類中的__init__,並不會自動呼叫父類的
obj = Teacher('dream', 'male', 18, '高階講師')
print(obj.name, obj.sex, obj.age, obj.title)
# dream male 18 高階講師
【3】繼承方式二
- 呼叫super()會得到一個特殊的物件
- 該物件專門用來引用父類的屬性
- 且嚴格按照MRO規定的順序向後查詢
class People:
school = '清華大學'
def __init__(self, name, sex, age):
self.name = name
self.sex = sex
self.age = age
class Teacher(People):
# 派生 : 派生出自己新的屬性,在進行屬性查詢時,子類中的屬性名會優先於父類被查詢
def __init__(self, name, sex, age, title):
# 直接呼叫 父類 中 的 __init__ 方法
# 呼叫的是繫結方法,因此會自動傳入self,但是需要傳入相應的引數
super().__init__(name, sex, age)
self.title = title
def teach(self):
print('%s is teaching' % self.name)
# 只會找自己類中的__init__,並不會自動呼叫父類的
obj = Teacher('dream', 'male', 18, '高階講師')
print(obj.name, obj.sex, obj.age, obj.title)
# dream male 18 高階講師
【六】組合
# 在一個類中以另外一個類的物件作為資料屬性,稱為類的組合。
class Course:
def __init__(self, name, period, price):
self.name = name
self.period = period
self.price = price
def tell_info(self):
print(f'當前課程名字 {self.name} 當前課程週期 {self.period} 當前課程價格 {self.price}')
class Date:
def __init__(self, year, mon, day):
self.year = year
self.mon = mon
self.day = day
def tell_birth(self):
print(f'當前生日 {self.year} 年 {self.mon} 月 {self.day} 日')
class People:
school = '清華大學'
def __init__(self, name, sex, age):
self.name = name
self.sex = sex
self.age = age
# Teacher類基於繼承來重用People的程式碼
# 基於組合來重用Date類和Course類的程式碼
class Teacher(People):
# 老師是人
def __init__(self, name, sex, age, title, year, mon, day):
super().__init__(name, age, sex)
# 老師有生日
self.birth = Date(year, mon, day)
# 老師有課程,可以在例項化後,往該列表中新增Course類的物件
self.courses = []
def teach(self):
print(f'當前老師正在授課 {self.name}')
python = Course('python', '3mons', 3000.0)
linux = Course('linux', '5mons', 5000.0)
teacher1 = Teacher('dream', 'male', 18, '金牌講師', 1987, 3, 23)
# teacher1有兩門課程
teacher1.courses.append(python)
teacher1.courses.append(linux)
# 重用Date類的功能
teacher1.birth.tell_birth()
# 重用Course類的功能
for obj in teacher1.courses:
obj.tell_info()
# 當前生日 1987 年 3 月 23 日
# 當前課程名字 python 當前課程週期 3mons 當前課程價格 3000.0
# 當前課程名字 linux 當前課程週期 5mons 當前課程價格 5000.0
【六】組合和繼承的區別
- 組合與繼承都是有效地利用已有類的資源的重要方式。但是二者的概念和使用場景皆不同,
【1】繼承的方式
- 透過繼承建立了派生類與基類之間的關係,它是一種'是'的關係,比如白馬是馬,人是動物。
- 當類之間有很多相同的功能,提取這些共同的功能做成基類,用繼承比較好,比如老師是人,學生是人
【2】組合的方式
- 用組合的方式建立了類與組合的類之間的關係,它是一種‘有’的關係,比如教授有生日,教授教python和linux課程,教授有學生s1、s2、s3...