Python中的面向對象編程
背景:
? 最近在看一些代碼的時候,對類中的一些內置方法不是很懂,因此出一篇文章來細說一下,希望大家看完后對Python中類有一個清楚的認識。
基礎鋪墊:
? 面向對象的三個特點:封裝、繼承、多態。面向對象的好處無非就是增加代碼的復用性,利于維護和修改,這也是高內聚,低耦合的體現。
- 封裝:
- 封裝是一種將數據(屬性)和操作數據的方法(方法)封裝在一個單元內的機制。
- 類的成員變量可以設置為私有,只能通過類的方法來訪問和修改。
- 繼承:
- 繼承允許你創建一個新類,該類繼承了一個現有類的屬性和方法。新類稱為子類,原始類稱為父類或基類。
- 子類可以擴展或修改繼承的屬性和方法,也可以添加新的屬性和方法。
- 多態:
- 多態性允許不同類的對象對相同的方法名做出不同的響應。這是通過方法的重寫和接口的實現來實現的。
類的特性:
Python使用class關鍵字來定義類,其基本結構如下:
-
class 類名(): #一般類名首字母是大寫pass
內置方法合集(重點):
? 內置方法(也稱為魔術方法或雙下劃線方法),它們具有特殊的含義和用途,為什么你有的時候看不懂一些方法,因為他是固定的,比較便捷,我們只需要對其重寫即可。
__init__(self, ...)
: 這是一個類的構造方法,用于初始化對象的屬性。當你創建一個類的新實例時,__init__
方法會自動調用,進行相關的賦值操作。__str__(self)
: 用于返回一個可讀的對象字符串表示。當你使用print
函數打印一個對象時,它會自動調用__str__
方法來獲取字符串表示,我們一般對其重寫。__repr__(self)
: 用于返回一個對象的官方字符串表示。通常,它應該返回一個字符串,以用于創建相同對象的副本。__len__(self)
: 這用于返回對象的長度。你可以通過內置函數len()
來獲取對象的長度,它會自動調用__len__
方法。__getitem__(self, key)
: 這用于允許對象像字典或列表一樣通過索引或鍵來訪問其元素。它用于實現對象的索引訪問。__setitem__(self, key, value)
: 用于允許對象像字典或列表一樣通過索引或鍵來設置其元素的值。它用于實現對象的索引賦值。__delitem__(self, key)
: 用于允許對象像字典或列表一樣通過索引或鍵來刪除其元素。它用于實現對象的索引刪除。
class Book:# self 是調用者def __init__(self, title, author, pages): # Book類內置屬性 標題 作者 頁數self.title = titleself.author = authorself.pages = pagesdef __str__(self):return f"{self.title} by {self.author}"def __repr__(self):return f"Book({self.title}, {self.author}, {self.pages})"def __len__(self):return self.pagesdef __getitem__(self, page_number):if page_number >= 1 and page_number <= self.pages:return f"Page {page_number} of {self.title}"else:raise IndexError("Page number out of range")def __iter__(self):self.current_page = 1 # 封裝一個屬性return selfdef __next__(self):if self.current_page <= self.pages:result = f"Page {self.current_page} of {self.title}"self.current_page += 1return resultelse:raise StopIteration
# 創建一個Book對象
book = Book("Python Basics", "John Smith", 100) #會自動調用 __init__ 方法# 使用內置方法
# 打印對象 會自動調用__str__
print(book) # 輸出: Python Basics by John Smith
# 調用__len__ 函數
print(len(book)) #輸出 100
# 調用__repr__ 函數
print(repr(book)) # 輸出: Book(Python Basics, John Smith, 100)
# __getitem__ 當取某一個元素得時候會自動調用
print(book[1]) # 輸出: Page 1 of Python Basics
print(book[50]) # 輸出: Page 50 of Python Basics
# # 迭代書的頁面
for page in book:print(page)# 第一次調用會執行__iter__函數,然后不斷使用__next__ 函數,for page in book:會反復調用 __next__ 方法,每次迭代都會獲取下一頁的頁面信息,直到沒有更多的頁面可供迭代為止。
組合:
? 組合指的是,在一個類中以另外一個類的對象作為數據屬性,稱為類的組合
class Student():def __init__(self):# 將創建好的手機對象賦值給了phone這個實例變量self.phone = Phone('霸王別姬')class Phone():def __init__(self, movie_name):self.movie_name = movie_namedef playMovie(self):print('手機正在播放的電影是:', self.movie_name)s1 = Student()
s1.phone.playMovie()
繼承:
? 通過繼承,你可以創建一個新類(子類),它可以繼承另一個類(父類或基類)的屬性和方法。子類可以擴展或修改父類的功能,并可以添加自己的屬性和方法。
- 父類和子類:
- 父類是被繼承的類,也被稱為基類或超類。
- 子類是繼承父類的類,也被稱為派生類。
- 繼承語法:
- 在子類的類定義中,將父類作為子類的參數傳遞給類定義。
- 使用
super()
函數可以在子類中調用父類的方法。
class ParentClass:def __init__(self, name):self.name = namedef speak(self):print(f"{self.name} is speaking.")class ChildClass(ParentClass):def __init__(self, name, age):super().__init__(name) # 調用父類的構造方法self.age = agedef speak(self):super().speak() # 調用父類的方法print(f"{self.name} is {self.age} years old and speaking.")child = ChildClass("Alice", 10)
child.speak()
class ParentClass:def __init__(self, name):self.name = nameclass ChildClass(ParentClass):def __init__(self, name, age):# 不顯式調用父類的構造方法,Python會自動調用self.age = agechild = ChildClass("Alice", 10)
print(child.name) # 輸出: Alice
print(child.age) # 輸出: 10
? 子類 ChildClass
的構造方法沒有顯式調用 super().__init__(name)
,但仍然可以正確地初始化 name
屬性,因為Python會自動調用父類 ParentClass
的構造方法。但是,如果你在子類的構造方法中想做一些其他特定于子類的初始化工作,你可以顯式調用 super().__init__(name)
來確保父類的構造方法也被執行。
多態:
class Animal:def speak(self):passclass Dog(Animal):def speak(self):return "Woof!"class Cat(Animal):def speak(self):return "Meow!"def make_animal_speak(animal):return animal.speak()dog = Dog()
cat = Cat()print(make_animal_speak(dog)) # 輸出: "Woof!" 調用誰得對象,執行who得函數
print(make_animal_speak(cat)) # 輸出: "Meow!"
實例變量和類變量:
實例變量:
- 實例變量指的是實例化對象本身擁有的變量。
- 通過實例名加圓點的方式調用實例變量 對象.屬性
class Student():def __init__(self,i_name,i_age):#只要定義在init方法內部的變量就是【實例/對象變量】self.name = i_name #self.name就是定義的實例變量,name是init方法的參數值self.age = i_age #self.age就是定義的實例變量,age就是init方法的參數值s1 = Student('xxx',21) #調用Student類中的init這個構造方法
s2 = Student('lisi',225)
print(s1.name,s1.age) #訪問s1對象的name和age這兩個實例變量
print(s2.name,s2.age) #訪問s2對象的name和age這兩個實例變量
類變量:
? 顧名思義,類和實例化對象公用得屬性叫做類變量。定義在類中,方法之外的變量,稱作類變量。類變量是所有實例公有的變量,每一個實例都可以訪問類變量。
class Student():# 定義在方法外部的變量:類變量address = 'Beijing'classroom = 167def __init__(self, i_name, i_age):# 只要定義在init方法內部的變量就是【實例/對象變量】self.name = i_nameself.age = i_ages1 = Student('zhangsan', 20) # 調用Student類中的init這個構造方法
s2 = Student('lisi', 25)
# 根據對象的引用訪問對象的實例變量
print(s1.name, s1.age) # 訪問s1對象的name和age這兩個實例變量
print(s2.name, s2.age) # 訪問s2對象的name和age這兩個實例變量
print(s1.address, s1.classroom) # 對象訪問類變量
print(Student.address,Student.classroom) # 類訪問類變量
一句話:類變量是可以被所有的對象公用的
類的方法:
? Python的類中可以包含三種不同類型的方法:實例方法、靜態方法和類方法。它們之間的區別主要涉及參數和調用方式,
實例方法:
- 實例方法是最常見的方法類型,在類內部定義時,第一個參數通常是
self
,它表示對象自身。 - 實例方法可以訪問和修改對象的屬性,因為它們有對當前實例的引用。
class Student():classroot = 167 #類變量#構造方法def __init__(self,name,age):#實例變量self.name = nameself.age = age#注意:實例方法只可以通過對象調用。def study(self,book):print('正在學習的書籍是:',book)s = Student('zhangsan',20) #實例化對象
#只給除了self其他的參數傳值
s.study('C++程序設計')
靜態方法:
- 靜態方法在類內部定義時,使用
@staticmethod
裝飾器來標識,它們不需要訪問對象的狀態,因此沒有self
參數。 - 靜態方法通常用于類級別的操作,而不是實例級別的操作。
class Obj():def __init__(self):pass# 定義一個靜態方法@staticmethoddef staticFunc(name): # 靜態方法不需要有任何的必要參數(self)print('我是靜態方法!,我有一個普通參數:', name)Obj.staticFunc('帥哥') # 通過類名調用(推薦)
o = Obj()
o.staticFunc('小帥哥') # 通過對象名調用(不推薦)
類方法:
- 類方法在類內部定義時,使用
@classmethod
裝飾器來標識,它們的第一個參數通常是cls
,它表示類本身。 - 類方法可以訪問和修改類級別的屬性,通常用于創建、操作或修改類級別的狀態。
class Obj():f = 'classVar' # 類變量def __init__(self):pass@classmethoddef classFunc(cls): # 類方法必須要有一個cls的參數,且作為第一個參數# cls也不是python的關鍵字,cls也可以寫作其他的形式,比如:xx,selfprint('我是類方法!必要參數cls的值為:', cls)print('類變量的值為:', cls.f) # 類名訪問類變量o = Obj()
o.classFunc() # 通過對象名訪問(不推薦)Obj.classFunc() # 通過類名訪問(推薦)