Python 類和對象:從 "圖紙" 到 "實物" 的編程思維
? ? ? ? 面向對象編程(Object-Oriented Programming,簡稱OOP )是一種通過組織對象來編程的方法。
1.初識類和對象:用生活例子看透核心概念
?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 = agedef 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 = agedef introduce(self):print(f"My name is {self.name} and I am {self.age} years old.")person1 = Person("Alice", 25)
person2 = Person("Bob", 30)
一句話總結:
- 類是 "模板",定義共性;對象是 "實例",有自己的個性。
- 就像 "汽車類" 是模板,你家的 "特斯拉" 和鄰居的 "比亞迪" 是對象。
?
2.屬性和方法
????????類的屬性和方法是類的核心組成部分,它們用于定義類的狀態和行為。
2.1屬性:對象的 "特征" 分類
????????屬性是對象的特征(比如名字、年齡、顏色),按歸屬可分為實例屬性和類屬性。
2.1.1實例屬性:每個對象獨有的特征
????????實例屬性是每個對象自己的 "個性特征"—— 不同對象可以有不同的值。
????????定義方式:在初始化方法__init__
中通過self.屬性名
定義。
class Dog:# 初始化方法:創建對象時自動調用,給對象設置初始屬性def __init__(self, name, age): # self代表當前對象self.name = name # 實例屬性:名字(每個狗不同)self.age = age # 實例屬性:年齡(每個狗不同)# 創建對象時傳入屬性值
dog1 = Dog("旺財", 3) # 旺財3歲
dog2 = Dog("小白", 2) # 小白2歲# 訪問實例屬性:對象名.屬性名
print(dog1.name) # 輸出:旺財
print(dog2.age) # 輸出:2
????????使用場景:描述對象的個性化特征(如人的姓名、手機的價格)。?
2.1.2類屬性:所有對象共享的特征
????????類屬性是類本身的屬性,所有對象共享同一個值 —— 改一次,所有對象都受影響。
????????定義方式:直接在類中定義(不在__init__
里)。
class Dog:# 類屬性:所有狗共享的特征(比如都屬于"犬科")species = "犬科" # 類屬性:定義在類中,不在__init__里def __init__(self, name):self.name = name # 實例屬性# 創建對象
dog1 = Dog("旺財")
dog2 = Dog("小白")# 訪問類屬性:類名.屬性名 或 對象名.屬性名
print(Dog.species) # 輸出:犬科(推薦用類名訪問)
print(dog1.species) # 輸出:犬科(對象也能訪問)# 修改類屬性:所有對象都會受影響
Dog.species = "哺乳綱犬科"
print(dog2.species) # 輸出:哺乳綱犬科
?????????使用場景:存儲所有對象的共性數據(如學生類的 "學校名稱"、汽車類的 "燃料類型")。
2.2方法:對象的 "功能" 分類
????????方法是對象的功能(比如說話、計算、移動),按作用范圍可分為實例方法、類方法和靜態方法。
2.2.1實例方法:操作對象自身的功能
????????實例方法是對象自己的功能,必須依賴具體對象才能調用,能訪問實例屬性和類屬性。
- 定義方式:
????????第一個參數必須是self
(代表當前對象)。
- 調用
????????實例.實例方法名(調用傳參)
或
類名.實例方法名(實例, 調用傳參)
class 類名(繼承列表):def 實例方法名(self, 參數1, 參數2, ...):"文檔字符串"語句塊
示例1:
class Dog:def __init__(self, name):self.name = name # 實例屬性# 實例方法:狗叫(依賴具體對象的名字)def bark(self):print(f"{self.name}:汪汪!") # 訪問實例屬性self.name# 實例方法:吃食物(帶參數)def eat(self, food):print(f"{self.name}在吃{food}")# 創建對象
dog = Dog("旺財")# 調用實例方法:對象名.方法名()
dog.bark() # 輸出:旺財:汪汪!
dog.eat("骨頭") # 輸出:旺財在吃骨頭
?????????使用場景:需要操作對象自身屬性的功能(如人的 "自我介紹"、手機的 "撥打電話")。
示例2:
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.2.2?類方法:操作類屬性的功能
類方法屬于類本身,不依賴具體對象,主要用于操作類屬性。
說明
類方法需要使用@classmethod裝飾器定義
類方法至少有一個形參用于綁定類,約定為 $cls$
類和該類的實例都可以調用類方法
類方法不能訪問此類創建的對象的實例屬
示例1
class School:# 類屬性:學生總數total_students = 0# 類方法:增加學生數量(操作類屬性)@classmethoddef add_student(cls): # cls代表School類cls.total_students += 1 # 修改類屬性# 類方法:獲取學生總數@classmethoddef get_total(cls):return cls.total_students# 調用類方法:類名.方法名()(不需要創建對象)
School.add_student() # 增加1個學生
School.add_student() # 再增加1個
print(School.get_total()) # 輸出:2
示例2
class A:v = 0@classmethoddef set_v(cls, value):cls.v = value@classmethoddef get_v(cls):return cls.vprint(A.get_v())
A.set_v(100)
print(A.get_v())
a = A()
print(a.get_v())
- 示例3
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}")# 創建類的實例
obj = MyClass(5)# 調用類方法修改類屬性
MyClass.modify_class_attr(20) # 輸出: 類屬性已修改為: 20
MyClass.try_modify_instance_attr() # 事出反常必有妖
????????使用場景:需要修改或查詢類屬性的功能(如統計類的實例數量、批量修改共性參數)。?
2.2.3?靜態方法:類中的 "工具函數"
靜態方法定義在類的內部,作用域是類內部
說明
使用@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
示例2:
class Calculator:# 靜態方法:計算兩個數的和(純工具功能)@staticmethoddef add(a, b):return a + b# 靜態方法:計算兩個數的積@staticmethoddef multiply(a, b):return a * b# 調用靜態方法:類名.方法名() 或 對象名.方法名()
print(Calculator.add(2, 3)) # 輸出:5
calc = Calculator()
print(calc.multiply(4, 5)) # 輸出:20
?
2.5.1 綜合應用
小案例:
class BankAccount:interest_rate = 0.05 # 類屬性def __init__(self, balance):self.balance = balancedef apply_interest(self): # 實例方法self.balance *= (1 + self.interest_rate)@classmethoddef set_interest_rate(cls, rate): # 類方法cls.interest_rate = rate@staticmethoddef validate_amount(amount): # 靜態方法return amount > 0 # 只是個工具方法,不依賴實例/類# 使用類方法修改利率
BankAccount.set_interest_rate(0.07)# 創建賬戶
acc = BankAccount(1000)
acc.apply_interest()
print(acc.balance) # 1070.0# 使用靜態方法驗證金額
print(BankAccount.validate_amount(-500)) # False
使用場景:邏輯上屬于類,但不依賴類或對象的工具功能(如數學計算、數據驗證)。?
3.構造與初始化:對象的 "出生過程"
????????創建對象時,Python 會自動執行兩個特殊方法:__new__
(造對象)和__init__
(初始化屬性)。
3.1?__new__
:創建對象的 "產房"
構造方法__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)
3.2初始化方法__init__
:給對象 "裝零件"
一旦對象被創建,Python會調用
__init__()
來初始化對象的屬性。- 必須有
self
參數,代表剛創建的對象。 - 可以定義其他參數,創建對象時傳入。
語法格式:
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__ 方法,初始化對象
'''
4.魔術方法:讓對象 "懂規矩" 的特殊技能
????????魔術方法是一種特殊的方法,用雙下劃線包裹,例如__init__
,__str__
,__add__
等。這些方法允許您自定義類的行為,以便與內置Python功能(如+運算符、迭代、字符串表示等)交互。
4.1?__str__
:自定義對象的 "自我介紹"
????????當用print()
或str()
輸出對象時,會自動調用__str__
,返回一個用戶友好的字符串。
class Person:def __init__(self, name, age):self.name = nameself.age = age# 自定義打印格式def __str__(self):return f"我叫{self.name},今年{self.age}歲"p = Person("小明", 18)
print(p) # 輸出:我叫小明,今年18歲(自動調用__str__)
print(str(p)) # 輸出:我叫小明,今年18歲(同樣調用__str__)
4.2?__repr__
:給開發者看的 "官方說明"
????????當用repr()
查看對象時,會調用__repr__
,返回一個能重建對象的字符串(通常是代碼形式)。
class Person:def __init__(self, name, age):self.name = nameself.age = age# 開發者友好的格式(可直接復制創建對象)def __repr__(self):return f"Person('{self.name}', {self.age})"p = Person("小紅", 20)
print(repr(p)) # 輸出:Person('小紅', 20)(適合調試)
小技巧:如果沒定義__str__
,print()
會用__repr__
的結果。
4.3?__add__
:讓對象支持 "+" 運算
????????自定義兩個對象相加的邏輯,用+
時自動調用。
class Point:def __init__(self, x, y):self.x = x # x坐標self.y = y # y坐標# 自定義加法:兩個點的x、y分別相加def __add__(self, other):return Point(self.x + other.x, self.y + other.y)# 配合打印,定義__repr__def __repr__(self):return f"Point({self.x}, {self.y})"p1 = Point(1, 2)
p2 = Point(3, 4)
p3 = p1 + p2 # 自動調用__add__
print(p3) # 輸出:Point(4, 6)
4.4?__sub__
:讓對象支持 "-" 運算
????????類似__add__
,自定義減法邏輯。
class Point:def __init__(self, x, y):self.x = xself.y = y# 自定義減法def __sub__(self, other):return Point(self.x - other.x, self.y - other.y)def __repr__(self):return f"Point({self.x}, {self.y})"p1 = Point(5, 5)
p2 = Point(2, 1)
print(p1 - p2) # 輸出:Point(3, 4)
4.5?__len__
:讓對象支持len()
函數
????????自定義len()
的返回值,通常用于表示對象的 "長度"。
class MyList:def __init__(self, items):self.items = items # 存儲列表數據# 自定義len()的結果為列表長度def __len__(self):return len(self.items)my_list = MyList([1, 2, 3, 4])
print(len(my_list)) # 輸出:4(自動調用__len__)
4.6?__getitem__
:讓對象支持 "[]" 索引
????????自定義通過索引(如obj[0]
)訪問對象的邏輯。
class MyList:def __init__(self, items):self.items = items# 自定義索引訪問:返回對應位置的元素def __getitem__(self, index):return self.items[index]my_list = MyList([10, 20, 30])
print(my_list[1]) # 輸出:20(自動調用__getitem__)
4.7?__setitem__
:讓對象支持 "[]=" 賦值
????????自定義通過索引(如obj[0] = 5
)修改對象的邏輯。
class MyList:def __init__(self, items):self.items = itemsdef __setitem__(self, index, value):self.items[index] = value # 修改對應位置的元素my_list = MyList([10, 20, 30])
my_list[1] = 200 # 自動調用__setitem__
print(my_list.items) # 輸出:[10, 200, 30]
4.8?__delitem__
:讓對象支持 "del" 刪除
????????自定義通過del obj[0]
刪除元素的邏輯。
class MyList:def __init__(self, items):self.items = itemsdef __delitem__(self, index):del self.items[index] # 刪除對應位置的元素my_list = MyList([10, 20, 30])
del my_list[0] # 自動調用__delitem__
print(my_list.items) # 輸出:[20, 30]
4.9?__iter__
和__next__
:讓對象支持 for 循環
????????實現這兩個方法,對象就可以被 for 循環遍歷(成為迭代器)。
class Counter:def __init__(self, end):self.end = end # 計數終點self.current = 0 # 當前計數# 迭代器必須返回自己def __iter__(self):return self# 每次迭代返回下一個值def __next__(self):if self.current < self.end:self.current += 1return self.currentelse:# 停止迭代raise StopIteration# 用for循環遍歷Counter對象
for num in Counter(3):print(num) # 輸出:1 → 2 → 3
4.10?__eq__
:自定義 "==" 比較邏輯
????????默認==
比較對象的內存地址,用__eq__
可自定義比較規則。
class Student:def __init__(self, id, name):self.id = id # 學號(唯一標識)self.name = name# 自定義相等:學號相同則認為相等def __eq__(self, other):return self.id == other.ids1 = Student(1001, "小明")
s2 = Student(1001, "小紅") # 學號相同
s3 = Student(1002, "小明") # 學號不同print(s1 == s2) # 輸出:True(學號相同)
print(s1 == s3) # 輸出:False(學號不同)
4.11?__lt__
和__gt__
:自定義 "<" 和 ">" 比較
????????__lt__
定義小于邏輯,__gt__
定義大于邏輯。
class Product:def __init__(self, price):self.price = price# 自定義小于:價格小則認為小def __lt__(self, other):return self.price < other.price# 自定義大于:價格大則認為大def __gt__(self, other):return self.price > other.pricep1 = Product(100)
p2 = Product(200)print(p1 < p2) # 輸出:True(100 < 200)
print(p1 > p2) # 輸出:False(100 > 200不成立)
4.12?__call__
:讓對象像函數一樣被調用
????????定義__call__
后,對象可以用對象名()
的形式調用。
class Adder:def __init__(self, num):self.num = num # 基礎數字# 讓對象可調用:傳入x,返回x + numdef __call__(self, x):return x + self.numadd5 = Adder(5) # 創建一個"加5"的對象
print(add5(3)) # 輸出:8(相當于調用函數,3+5)
print(add5(10)) # 輸出:15(10+5)
5、實戰練習:鞏固類和對象的知識
設計一個 "圖書" 類
- 實例屬性:書名(name)、作者(author)、頁數(pages)
- 類屬性:類別(category = "書籍")
- 實例方法:
get_info()
?打印圖書信息 - 類方法:
set_category(new_cat)
?修改類別 - 魔術方法:
__str__
?自定義打印格式
class Book:category = '書籍'def __init__(self, name, autor, pages):"""初始化圖書對象參數:name: 書名author: 作者pages: 頁數"""self.name = nameself.autor = autorself.pages = pagesdef get_info(self):"""返回格式化的圖書信息字符串"""return f'書名:{self.name}, 作者:{self.autor}, 頁數{self.pages}'@classmethoddef set_category(cls, new_cat):"""修改圖書類別"""cls.category = new_catdef __str__(self):"""返回圖書的簡短描述"""return f'{self.name} ({self.autor}著)'book = Book("Python 編程", "張三", 300)
print(book) # 輸出:Python 編程(張三 著)
book.get_info() # 輸出:書名:Python 編程...
print(Book.category) # 輸出:書籍
Book.set_category("技術圖書")
print(book.category) # 輸出:技術圖書
總結:類和對象是編程的 "積木"
????????類和對象是面向對象編程的核心,它們讓代碼更貼近現實世界的邏輯:
- 用類定義 "模板",用對象創建 "實物";
- 用屬性描述特征,用方法定義功能;
- 用魔術方法讓對象支持 Python 的內置功能,更 "合群"。
????????學會類和對象后,你可以用更模塊化、更易維護的方式編寫復雜程序 —— 就像用積木搭房子,先做好基礎零件(類),再組合出各種造型(程序)。