二、面向對象編程
面向對象編程(Object-Oriented Programming,簡稱OOP)是一種通過組織對象來設計程序的編程方法。
Python天生就是面向對象的模塊化編程。
1. 初識類和對象
示意圖:
/-------> BYD E6(京A.88888) 實例,對象 車(類) ?\-------> BMW X5(京B.00000) 實例(對象)/-------> 小京巴(戶籍號:000001) 狗(類) ?\-------> 導盲犬(戶籍號:000002) ?/-------> 100 (對象) int(類) ?\-------> 200 (對象)
1.1 類→Class
物以類聚
1.1.1 概念
類是對一類對象的抽象,是對象的模板或藍圖。它定義了對象的屬性(特征)和方法(功能)。
1.1.2 創建
數據成員:表明事物的特征。 相當于變量
方法成員:表明事物的功能。 相當于函數
通過
class
關鍵字定義類。類的創建語句語法:
class 類名 (繼承列表):實例屬性(類內的變量) 定義實例方法(類內的函數method) 定義類變量(class variable) 定義類方法(@classmethod) 定義靜態方法(@staticmethod) 定義
參考代碼:
class Dog:def __init__(self, name, age):self.name = nameself.age = age ?def bark(self):print(f"{self.name} says Woof!")
類名就是標識符,建議(有點強烈)首字母大寫
類名實質上就是變量,它綁定一個類
self代表類實例化的對象本身
1.2 對象→Object
人以群分,每個人就是一個對象。
1.2.1 概念
對象是類的實例化,是類的實際數據存儲,具有類所定義的屬性和方法
1.2.2 創建
構造函數調用表達式
變量 = 類名([參數])
說明
變量存儲的是實例化后的對象地址
類參數按照初始化方法的形參傳遞
對象是類的實例,具有類定義的屬性和方法。
通過調用類的構造函數來創建對象。
每個對象有自己的狀態,但共享方法。
示例代碼
class Dog:pass ? # 創建第一個實例: dog1 = Dog() print(id(dog1)) ?# 打印這個對象的ID # 創建第二個實例對象 dog2 = Dog() ?# dog2 綁定一個Dog類型的對象 print(id(dog2)) ? ? class Person:def __init__(self, name, age):self.name = nameself.age = age ?def introduce(self):print(f"My name is {self.name} and I am {self.age} years old.")person1 = Person("Alice", 25) person2 = Person("Bob", 30)
類和對象的關系:
類是對象的模板或藍圖,定義了對象的屬性和行為。
對象是類的實例,是根據類創建的具體實體。
同一個類可以創建多個對象,每個對象都有自己的狀態。例如,一個Dog類可以創建多個 Dog 對象,每個對象有不同的 name 和 age。
2. 屬性和方法
類的屬性和方法是類的核心組成部分,它們用于定義類的狀態和行為。
2.1 實例屬性
每個實例有自己的變量,稱為實例變量(也叫屬性)
屬性的使用語法
實例.屬性名
屬性使用
class Dog:def eat(self, food):print(self.color, '的', self.kinds, '正在吃', food) ? # 創建一個實例: dog1 = Dog() dog1.kinds = "京巴" ?# 添加屬性 dog1.color = "白色" dog1.color = "黃色" ?# 修改屬性 print(dog1.color, '的', dog1.kinds) ? dog2 = Dog() dog2.kinds = "藏獒" dog2.color = "棕色" print(dog2.color, '的', dog2.kinds)
實例方法和實例屬性(實例變量)結合在一起用
class Dog:def eat(self, food):print(self.color, '的', self.kinds, '正在吃', food) ? # 創建第一個對象 dog1 = Dog() dog1.kinds = '京巴' ?# 添加屬性kinds dog1.color = '白色' ?# 添加屬性color dog1.eat("骨頭") ? dog2 = Dog() dog2.kinds = '牧羊犬' dog2.color = '灰色' dog2.eat('包子')
2.2 實例方法
class 類名(繼承列表):def 實例方法名(self, 參數1, 參數2, ...):"文檔字符串"語句塊
實例方法就是函數,至少有一個指向實例對象的形參self
調用
實例.實例方法名(調用傳參) # 或 類名.實例方法名(實例, 調用傳參)
帶有實例方法的簡單的Dog類
class Dog:"""這是一個種小動物的定義這種動物是狗(犬)類,用于創建各種各樣的小狗""" ?def eat(self, food):"""此方法用來描述小狗吃東西的行為"""print("小狗正在吃", food) ?def sleep(self, hour):print("小狗睡了", hour, "小時!") ?def play(self, obj):print("小狗正在玩", obj) ? ? dog1 = Dog() dog1.eat("骨頭") dog1.sleep(1) dog1.play('球') ? help(Dog) ?# 可以看到Dog類的文檔信息
2.3 類屬性
類屬性是類的屬性,此屬性屬于類,不屬于此類的實例
作用:
通常用來存儲該類創建的對象的共有屬性
類屬性說明
類屬性,可以通過該類直接訪問
類屬性,可以通過類的實例直接訪問
類屬性示例
class Human:total_count = 0 ?# 創建類屬性 self.name = namedef __init__(self, name):self.name = name ? print(Human.total_count) h1 = Human("小張") print(h1.total_count)
2.4 類方法
類方法是用于描述類的行為的方法,類方法屬于類,不屬于該類創建的對象
說明
類方法需要使用@classmethod裝飾器定義
類方法至少有一個形參用于綁定類,約定為 $cls$
類和該類的實例都可以調用類方法
類方法不能訪問此類創建的對象的實例屬性
類方法示例1
class A:v = 0@classmethoddef set_v(cls, value): # def fun01(self)cls.v = value@classmethoddef get_v(cls):return cls.v print(A.get_v()) A.set_v(100) print(A.get_v()) a = A() print(a.get_v())
類方法示例2
class MyClass:class_attr = 0 ?# 類屬性 ?def __init__(self, value):self.instance_attr = value ?# 實例屬性 ?@classmethoddef modify_class_attr(cls, new_value):cls.class_attr = new_valueprint(f"類屬性已修改為: {cls.class_attr}") ?@classmethoddef try_modify_instance_attr(cls):try:cls.instance_attr = 10 ?# 嘗試修改實例屬性(會失敗)except AttributeError as e:print(f"錯誤: {e}") ?def show_attrs(self):print(f"實例屬性: {self.instance_attr}")print(f"類屬性: {self.class_attr}") ? # 創建類的實例 obj = MyClass(5) ? # 調用類方法修改類屬性 MyClass.modify_class_attr(20) ?# 輸出: 類屬性已修改為: 20 obj.show_attrs() # 輸出: # 實例屬性: 5 # 類屬性: 20 ? # 調用類方法嘗試修改實例屬性 MyClass.try_modify_instance_attr() # 輸出: 錯誤: type object 'MyClass' has no attribute 'instance_attr' ? # 嘗試調用類方法修改實例屬性 obj.try_modify_instance_attr() # 輸出: 錯誤: type object 'MyClass' has no attribute 'instance_attr'
cls說明
在Python中,cls
是一個約定俗成的名稱,用于表示類本身。在類方法(使用 @classmethod
裝飾的方法)中,cls
作為第一個參數傳遞給方法。這使得類方法可以訪問和修改類屬性以及調用其他類方法,而不需要引用具體的實例。
cls
的作用
訪問類屬性:類方法可以通過
cls
訪問和修改類屬性。調用類方法:類方法可以通過
cls
調用其他類方法。創建類實例:類方法可以使用
cls
來創建類的實例。
2.5 靜態方法
靜態方法定義在類的內部,作用域是類內部
說明
使用@staticmethod裝飾器定義
不需要self和cls參數
通過類或類實例調用
可以訪問類屬性,不能訪問實例屬性
靜態方法示例
class A:class_attr = 42 ?# 類屬性 ?def __init__(self, value):self.instance_attr = value ?# 實例屬性 ?@staticmethoddef myadd(a, b):# 只能訪問傳遞的參數,不能訪問實例屬性return a + b ? # 創建類實例 a = A(10) ? # 調用靜態方法 print(A.myadd(100, 200)) ?# 輸出: 300 print(a.myadd(300, 400)) ?# 輸出: 700 ? ? # 嘗試在靜態方法內訪問類屬性或實例屬性(會導致錯誤) class B:class_attr = 42 ?def __init__(self, value):self.instance_attr = value ?@staticmethoddef myadd(a, b):# return a + b + B.class_attr# 以下訪問會導致錯誤# return a + b + self.instance_attrreturn a + b ? # 創建類實例 b = B(10) ? # 調用靜態方法 print(B.myadd(100, 200)) ?# 輸出: 300 print(b.myadd(300, 400)) ?# 輸出: 700 ?
2.6 構造方法
構造方法__new__()
:
負責對象的 創建 和內存分配的。
在對象實例化時被調用,負責返回一個新的對象實例。
通常不需要顯式地定義
__new__()
方法,Python會調用基類 $object$ 的__new__()
方法。
class MyClass:def __new__(cls, *args, **kwargs):print("調用 __new__ 方法,創建對象")return super().__new__(cls) ?def __init__(self, value):print("調用 __init__ 方法,初始化對象")self.value = value ? ? # 創建對象 obj = MyClass(10)
2.7 初始化方法
一旦對象被創建,Python會調用
__init__()
來初始化對象的屬性。語法格式:
class 類名(繼承列表):def __init__(self[, 形參列表]):語句塊 # [] 代表其中的內容可省略
接收實參到
__init__
方法中代碼示例:
class MyClass:def __new__(cls, *args, **kwargs):print("調用 __new__ 方法,創建對象")return super().__new__(cls) ?def __init__(self, value):print("調用 __init__ 方法,初始化對象")self.value = value ? # 創建對象 obj = MyClass(10)
輸出:
調用 __new__ 方法,創建對象 調用 __init__ 方法,初始化對象
2.8 魔術方法
魔術方法是一種特殊的方法,用雙下劃線包裹,例如__init__
,__str__
,__add__
等。這些方法允許您自定義類的行為,以便與內置Python功能(如+運算符、迭代、字符串表示等)交互。
2.8.1 常用方法
__init__(self, ...)
: 初始化對象,通常用于設置對象的屬性。__str__(self)
: 定義對象的字符串表示形式,可通過str(object)
或print(object)
調用。例如,您可以返回一個字符串,描述對象的屬性。__repr__(self)
: 定義對象的“官方”字符串表示形式,通常用于調試。可通過repr(object)
調用。__len__(self)
: 定義對象的長度,可通過len(object)
調用。通常在自定義容器類中使用。__getitem__(self, key)
: 定義對象的索引操作,使對象可被像列表或字典一樣索引。例如,object[key]
。__setitem__(self, key, value)
: 定義對象的賦值操作,使對象可像列表或字典一樣賦值。例如,object[key] = value
。__delitem__(self, key)
: 定義對象的刪除操作,使對象可像列表或字典一樣刪除元素。例如,del object[key]
。__iter__(self)
: 定義迭代器,使對象可迭代,可用于for
循環。__next__(self)
: 定義迭代器的下一個元素,通常與__iter__
一起使用。__add__(self, other)
: 定義對象相加的行為,使對象可以使用+
運算符相加。例如,object1 + object2
。__sub__(self, other)
: 定義對象相減的行為,使對象可以使用-
運算符相減。__eq__(self, other)
: 定義對象相等性的行為,使對象可以使用==
運算符比較。__lt__(self, other)
: 定義對象小于其他對象的行為,使對象可以使用<
運算符比較。__gt__(self, other)
: 定義對象大于其他對象的行為,使對象可以使用>
運算符比較。__call__(self, other)
是一個特殊的方法(也稱為“魔法方法”),它允許一個對象像函數一樣被調用。
2.8.2 案例參考
__str__()
:定義print()
或str()
函數調用時的輸出字符串表示。__str__()
方法用來定義當你調用print()
或str()
時對象應該返回的字符串。該方法必須返回一個字符串,通常用于給用戶可讀的對象描述。
示例:
class Person:def __init__(self, name, age):self.name = nameself.age = age ?def __str__(self):return f"Person: {self.name}, Age: {self.age}" ? p = Person("Alice", 30) print(p) ?# 輸出: Person: Alice, Age: 30
作用:
使得你的對象在打印時更加友好和可讀。
提供更好的調試輸出。
__repr__()
:定義repr()
函數的輸出,通常用于開發和調試,給出對象的正式字符串表示。__repr__()
方法用于返回一個可以用來重新創建對象的字符串,理想情況下,返回的字符串應當是合法的 Python 表達式。如果你沒有定義
__str__()
,那么__repr__()
會被用來替代str()
和print()
。
示例:
class Person:def __init__(self, name, age):self.name = nameself.age = age ?def __repr__(self):return f"Person('{self.name}', {self.age})" ? p = Person("Alice", 30) print(repr(p)) ?# 輸出: Person('Alice', 30)
作用:
__repr__()
是供開發人員使用的,輸出的字符串應該盡可能接近于可以創建該對象的代碼。在調試時使用
repr()
更加方便,它提供了一個清晰的對象表示。
__add__()
:定義 $+$ 運算符的行為。該方法允許你重載加法操作符
+
,使其在兩個對象之間執行加法時能夠自定義行為。
示例:
class Point:def __init__(self, x, y):self.x = xself.y = y ?def __add__(self, other):return Point(self.x + other.x, self.y + other.y) ?def __repr__(self):return f"Point({self.x}, {self.y})" ? p1 = Point(1, 2) p2 = Point(3, 4) p3 = p1 + p2 print(p3) ?# 輸出: Point(4, 6)
作用:
允許你自定義 $+$ 運算符的行為。
__len__()
:定義len()
函數的行為。__len__()
方法允許你自定義len()
函數的行為,返回對象的長度。
示例:
class MyList:def __init__(self, items):self.items = items ?def __len__(self):return len(self.items) ? my_list = MyList([1, 2, 3]) print(len(my_list)) ?# 輸出: 3
作用:
使得你的對象能夠與
len()
函數兼容,返回對象的長度。
__getitem__()
:定義對象支持索引([]
)操作。__getitem__()
方法使得對象能夠支持類似列表、元組那樣的索引操作。
示例:
class MyList:def __init__(self, items):self.items = items ?def __getitem__(self, index):return self.items[index] ? my_list = MyList([1, 2, 3, 4]) print(my_list[2]) ?# 輸出: 3
作用:
使對象能夠支持索引操作,類似于內置的數據結構(如列表、字典)。
__setitem__()
:定義對象支持索引賦值操作([] =
)。__setitem__()
方法允許你定義如何通過索引給對象賦值。
示例:
class MyList:def __init__(self, items):self.items = items ?def __setitem__(self, index, value):self.items[index] = value ? my_list = MyList([1, 2, 3]) my_list[1] = 10 print(my_list.items) ?# 輸出: [1, 10, 3]
作用:
使對象能夠支持索引賦值操作。
__del__()
:定義對象的析構方法,通常用于資源清理。這個方法在對象銷毀時調用,通常用于清理資源(如關閉文件、數據庫連接等)。
示例:
class MyClass:def __init__(self, name):self.name = nameprint(f"對象 {name} 創建") ?def __del__(self):print(f"對象 {self.name} 被銷毀") ? obj = MyClass("Test") del obj ?# 輸出: 對象 Test 被銷毀
作用:
用于對象銷毀時進行資源清理。