今日學習內容總結2.6
今日學習內容總結
在昨日的學習中,我們已經有了面向物件的程式設計思想。對類和物件有了一定程度的瞭解。物件,就是資料與功能的結合體,也是一個容器。類就是多個物件中相同資料與功能的結合體。其實也算是物件。在程式碼中,必須先定義類才能產生物件。今天我們就對面向物件程式設計做進一步的瞭解。
動態方法與靜態方法
靜態方法
用 @staticmethod 裝飾的不帶 self 引數的方法叫做靜態方法,類的靜態方法可以沒有引數,可以直接使用類名呼叫。
class Student: @staticmethod def speak(a): print(a) obj1 = Student() # 靜態方法就是一個普通的函式,只不過寫在類中需要自己傳參 # 類呼叫靜態方法 Student.speak(123) # 123 # 物件呼叫靜態方法 obj1.speak(321) # 321
靜態方法是類中的函式,不需要例項。靜態方法主要是用來存放邏輯性的程式碼,主要是一些邏輯屬於類,但是和類本身沒有互動,即在靜態方法中,不會涉及到類中的方法和屬性的操作。可以理解為將靜態方法存在此類的名稱空間中。並且,靜態函式可以通過類名以及例項兩種方法呼叫。
動態方法
動態方法是將類本身作為物件進行操作的方法。他和靜態方法的區別在於:不管這個方式是從例項呼叫還是從類呼叫,它都用第一個引數把類傳遞過來。
class ColorTest(object): color = "color" @classmethod def value(self): return self.color class Red(ColorTest): color = "red" class Green(ColorTest): color = "green" # 類呼叫繫結給類的方法:會自動將類當做第一個引數傳入 print(ColorTest) # <class '__main__.ColorTest'> g = Green() # 這是物件呼叫繫結給類的方法,不需要傳參,會將產生該物件的類自動當做第一個引數傳入 print(g.value()) # green print(Green.value()) # green
繼承
面向物件程式語言的一個主要功能就是繼承。繼承是指這樣一種能力:它可以使用現有類的所有功能,並在無需重新編寫原來的類的情況下對這些功能進行擴充套件。
class Person: def __init__(self, name, age, gender): self.name = name self.age = age self.gender = gender class Teacher(Person): def teach(self): print(f'{self.name}老師正在講課') class Student(Person): def study(self): print(f'{self.name}學生正在學習') stu1 = Student('jason', 18, 'male') stu1.study() # jason學生正在學習
通過繼承建立的新類稱為“子類”或“派生類”,被繼承的類稱為“基類”、“父類”或“超類”,繼承的過程,就是從一般到特殊的過程。在 python 語言中,一個子類可以繼承多個基類。在上述程式碼中,Person 類就是父類,Teacher和Student類就是子類。既然子類繼承了父類,那麼子類就全部擁有了父類的方法和屬性。但是,如果子類裡面有一個和父類同樣名稱的方法,那麼就把父類中的同一個方法遮蓋住了,顯示的是子類自己的方法,這叫做方法的重寫。例項化子類Student之後,執行示例方法study(),在繼承中基類的構造(init()方法)不會被自動呼叫,它需要在其派生類的構造中親自專門呼叫。在例項化的時候,需要傳完整的引數。不然會報錯。
查詢順序
在不繼承的情況下名字的查詢順序是先從物件自己的名稱空間中查詢,沒有則去類裡面的名稱空間查詢。
單繼承
# 名字查詢順序 通過案例檢視順序
class A:
def f1(self):
print('from A.f1')
def f2(self):
print('from A.f2')
self.f1()
class MyClass(A):
def f1(self):
print('from MyClass.f1')
obj = MyClass()
obj.f2()
# 執行的方法分別是A裡面的f2和MyClass裡面的f1
由例項可以看出,單繼承情況下名字的查詢順序是:先從物件自己的名稱空間中查詢,沒有則去產生物件的類中查詢,如果還沒有並且類有父類則去父類中查詢。
多繼承
在理解多繼承之前,我們可以瞭解一下python2和python3中多繼承情況下的區分。關鍵在於是否繼承了一個預設的object類。
多繼承,就是一個類繼承自多個類,它將具有多個類的特徵。查詢順序:
多繼承的查詢順序中,有深度優先的情況和廣度優先的情況。
深度優先:父類中名字的查詢順序就是按照繼承時從左往右依次查詢,如果多個父類還有分類則遵循深度優先。意思是。我們在多繼承的情況下查詢名字是從左往右一次查詢,如果最左邊的父類,還有父類。那麼查詢順序會繼續查詢最左邊的父類中的父類中有沒有這個名字。接下來才會繼續按照從左往右的順序。這就是深度優先。
廣度優先:在深度優先的基礎上,如果子類A,繼承了B,C,D三個父類,這三個父類又分別繼承了E,F,G三個父類,同時E,F,G繼承了同一個父類H。在查詢的時候,不會查詢到H。按照深度優先來查詢,最後查詢H。這就是廣度優先。
派生類
之前說過繼承中無需重新編寫原來的類的情況下對這些功能進行擴充套件:
class Person:
def __init__(self,name,age,gender):
self.name = name
self.age = age
self.gender = gender
class Teacher(Person):
def __init__(self,name,age,gender,level,salary):
# 用了Person類裡面的__init__方法之後
# super(Teacher,self).__init__(name,age,gender) # 子類呼叫父類的方法 完整語法
super().__init__(name,age,gender) # 子類呼叫父類的方法 精簡語法
# 自己還要新增一個額外的東西
self.level = level
self.salary = salary
這就是無需重新編寫原來的類的情況下對這些功能進行擴充套件的寫法,同時我們稱這樣的子類為派生類。本質上還是子類。可以通過關鍵字super實現。實現效果:
t1 = Teacher('jason',18,'male','高階',20)
print(t1.__dict__) # {'name': 'jason', 'age': 18, 'gender': 'male', 'level': '高階', 'salary': 20}