1. 程式人生 > >一文看懂Python的面向物件程式設計,這是真正的一篇非常棒的教程!

一文看懂Python的面向物件程式設計,這是真正的一篇非常棒的教程!

一文看懂Python的面向物件程式設計,這是真正的一篇非常棒的教程!

 

之前在網路上看了很多關於面向物件的程式設計詳解,還是不夠過癮,所以決定自己動手寫一篇。

面向物件:Object Oriented Programming,簡稱OOP,即面向物件程式設計。


                學習Python中有不明白推薦加入交流群
                號:516107834
                群裡有志同道合的小夥伴,互幫互助,
                群裡有不錯的學習教程!

類(Class)和物件(Object)

類是用來描述具有相同屬性和方法物件的集合。物件是類的具體例項。

比如,學生都有姓名和分數,那麼這個姓名和分數就是共同的屬性,這時就可以設計一個類,用來記錄學生的姓名和成績。

這裡解釋一下屬性和方法

  • 屬性:Attribute,用來描述所有物件公有的屬性,如學生的姓名和分數。
  • 方法:Method,包含在類裡面的函式,也叫類函式,區別於類之外的函式,用來實現某些功能,比如打印出學生的姓名和分數。

使用關鍵詞class來建立一個類

一文看懂Python的面向物件程式設計,這是真正的一篇非常棒的教程!

 

class Student():
 def __init__(self,name,score):
 self.name = name
 self.score = score
 def out(self):
 print("%s:%s"%(self.name,self.score))

一文看懂Python的面向物件程式設計,這是真正的一篇非常棒的教程!

 

以上案例中,只是定義了一個類,電腦並沒有建立儲存空間。

只有完成類的例項化,才能創建出類的具體的物件,併為之分配儲存空間。所以說,物件是類的一個例項。

接下來建立一個物件,只需要新增一下兩行程式碼即可實現

Student1 = Student('Anny','100')
Student2 = Student('Mike','90')

這樣一來,Student是類,student1和student2是建立的這個類的具體的物件。當有以上程式碼的時候,Python會自動呼叫__init__初始自構函式來建立具體的物件。關鍵字self是非常重要的引數,代表建立了函式本身。

當建立了具體的物件之後,就可以使用Student1.name和Student1.score來分別獲取該學生的姓名和分數,也可以直接呼叫方法Student1.out()來獲取所有資訊。

類變數與例項變數

假設現在需要新增一個計數器,每當新增一個學生時計數器就加1。

這個計數器不屬於某一個學生,而是屬於類的屬性,所以稱之為類。

而姓名和分數是屬於每個學生的,所以稱之為例項變數,也叫物件變數。

正常情況下,這樣新增一個計數器

一文看懂Python的面向物件程式設計,這是真正的一篇非常棒的教程!

 

class Student():
 
 number = 0
 
 def __init__(self,name,score):
 self.name = name
 self.score = score
 number = number + 1
 def show(self):
 print("%s:%s"%(self.name,self.score))
student1 = Student('Anny',100)
student2 = Student('Mike',90)
print(student1.name)

一文看懂Python的面向物件程式設計,這是真正的一篇非常棒的教程!

 

這裡的number是類變數,所以將其放置方法外邊,name和score是例項變數,所以將其放置方法裡面。

類變數和例項變數區別很大,訪問方式也不一樣。

  • 類變數:class variables,類變數在整個例項化的物件中是公用的,類變數定義在類中,且在函式體外。訪問或者呼叫類變數的具體方法是類名.變數名,或者self.__class__.變數名,self.__class__.自動返回每個物件的類名。
  • 例項變數:instance variables,定義在函式之內的變數,屬於某個具體的物件,訪問或者呼叫例項變數的方法是物件名.變數名,或者self.變數名。

執行上述程式碼會發現報錯

UnboundLocalError: local variable 'number' referenced before assignment

英語賊差,某道雲翻譯的:大致意思是區域性變數number的引用之前的任務

所以說,如果要呼叫屬於類的變數number,則使用Student.number或者self.__class__.number

修改如下

一文看懂Python的面向物件程式設計,這是真正的一篇非常棒的教程!

 

class Student():
 number = 0
 def __init__(self,name,score):
 self.name = name
 self.score = score
 Student.number = Student.number + 1
 def show(self):
 print("%s:%s"%(self.name,self.score))
student1 = Student('Anny',100)
student2 = Student('Mike',90)
student1.show()
print(student2.number)

一文看懂Python的面向物件程式設計,這是真正的一篇非常棒的教程!

 

類方法

有些變數只屬於類,有些方法也只屬於類,不屬於具體的物件。不難發現,在屬於物件的方法裡面都有self的引數,比如__init__(self)、show(self)等,而在類中,則使用cls,與self類似,它表示類本身,一般加上@classmethod的修飾符以作說明。

這裡使用自定義的類方法來列印學生的數量

一文看懂Python的面向物件程式設計,這是真正的一篇非常棒的教程!

 

class Student():
 number = 0
 def __init__(self,name,score):
 self.name = name
 self.score = score
 Student.number = Student.number + 1
 def show(self):
 print("%s:%s"%(self.name,self.score))
 @classmethod
 def people(cls):
 print("一共有%s名學生"%Student.number)
student1 = Student('Anny',100)
student2 = Student('Mike',90)
student1.show()
student2.show()
Student.people()

一文看懂Python的面向物件程式設計,這是真正的一篇非常棒的教程!

 

類的私有屬性和私有方法

類裡面的私有屬性和私有方法都是以雙下劃線__開頭的,私有屬性和方法不能在類的外部直接使用或訪問。將score變為私有屬性,然後print(Student.score),就會發現報錯。但是呼叫show的時候不會報錯,這是因為show是類裡面的函式,所以可以訪問私有變數。

私有方法也是同樣的道理,值得注意的是,私有方法必須含有self引數並且將其作為第一個引數。

在面向物件的程式設計中,通常很少讓外部類直接訪問類內部的屬性和方法,而是向外部提供一些按鈕,對其內部的成員進行訪問,以保證程式的安全性,這就叫封裝。

 @property
 def scores(self):
 print("該學生成績為%s"%self.score)

加上裝飾器之後不用加括號可直接呼叫。

類的繼承

面向物件程式設計最大的好處就是避免重複的程式碼,也就是將一段程式碼重複使用,方法之一就是繼承。

先定義一個基類或者父類,再通過class 類名(父類):pass建立子類,這樣一來,子類獲得了父類的所有屬性和方法,這種現象就叫做繼承。

再寫段程式碼,用Schoolmember表示父類,姓名和年齡是所有人的屬性,然而老師有工資(salary)這個專有屬性,學生有分數(score)這個專有屬性

一文看懂Python的面向物件程式設計,這是真正的一篇非常棒的教程!

 

# 建立父類學校成員SchoolMember
class SchoolMember:
 def __init__(self, name, age):
 self.name = name
 self.age = age
 def tell(self):
 # 列印個人資訊
 print('Name:"{}" Age:"{}"'.format(self.name, self.age), end=" ")
# 建立子類老師 Teacher
class Teacher(SchoolMember):
 def __init__(self, name, age, salary):
 SchoolMember.__init__(self, name, age) # 利用父類進行初始化
 self.salary = salary
 # 方法重寫
 def tell(self):
 SchoolMember.tell(self)
 print('Salary: {}'.format(self.salary))
# 建立子類學生Student
class Student(SchoolMember):
 def __init__(self, name, age, score):
 SchoolMember.__init__(self, name, age)
 self.score = score
 def tell(self):
 SchoolMember.tell(self)
 print('score: {}'.format(self.score))
teacher1 = Teacher("John", 44, "$60000")
student1 = Student("Mary", 12, 99)
teacher1.tell() # 列印 Name:"John" Age:"44" Salary: $60000
student1.tell() # Name:"Mary" Age:"12" score: 99

一文看懂Python的面向物件程式設計,這是真正的一篇非常棒的教程!

 

通過以上程式碼不難看出

  • 在建立子類的過程中,需要手動呼叫父類的建構函式__init__來完成子類的建立。
  • 在子類中呼叫父類的方法時,需加上父類的類名字首,且必須帶self引數變數。例SchoolMember.tell(self)。
  • 如果子類呼叫了每個方法或者屬性,Python會先在父類中尋找,找不到就會去子類尋找。

在實際的專案中,一個子類可以繼承多個父類。

使用super()關鍵字呼叫父類

在子類中可以使用super關鍵字直接呼叫父類中的屬性或者方法,簡化程式碼,也反映出人生苦短,我用Python的宗旨。

一文看懂Python的面向物件程式設計,這是真正的一篇非常棒的教程!

 

# 建立子類學生Student
class Student(SchoolMember):
 def __init__(self, name, age, score):
 SchoolMember.__init__(self, name, age)
 self.score = score
 def tell(self):
 super().tell() # 等同於 SchoolMember.tell(self)
 print('score: {}'.format(self.score))

以上的例子中,學生子類呼叫了父類的tell方法,等同於SchoolMember.tell(self),使用super關鍵字呼叫時,需去掉括號裡的self。

在網路和現實中,我都是孤獨的!