国产亚洲精品福利在线无卡一,国产精久久一区二区三区,亚洲精品无码国模,精品久久久久久无码专区不卡

當(dāng)前位置: 首頁(yè) > news >正文

網(wǎng)站前端設(shè)計(jì)重慶森林在線觀看

網(wǎng)站前端設(shè)計(jì),重慶森林在線觀看,企業(yè)網(wǎng)站建設(shè)咨詢,對(duì)網(wǎng)站做數(shù)據(jù)統(tǒng)計(jì)的目的是什么意思一、類和對(duì)象 1. 類和對(duì)象基礎(chǔ) 類(Class)的概念 類是對(duì)一類事物的抽象描述,定義了這類事物的屬性(數(shù)據(jù))和方法(行為)。 屬性:類的特征,如 “人” 的姓名、年齡。方法&am…

一、類和對(duì)象

1. 類和對(duì)象基礎(chǔ)

類(Class)的概念

是對(duì)一類事物的抽象描述,定義了這類事物的屬性(數(shù)據(jù))方法(行為)。

  • 屬性:類的特征,如 “人” 的姓名、年齡。
  • 方法:類的行為,如 “人” 的說(shuō)話、跑步。

類比現(xiàn)實(shí)

  • 類 = 設(shè)計(jì)圖紙(如 “汽車” 的設(shè)計(jì)圖)。
  • 對(duì)象 = 根據(jù)圖紙制造的具體實(shí)例(如 “一輛紅色的特斯拉汽車”)。

2、定義類的語(yǔ)法

class ClassName:# 類屬性(可選,屬于類本身)class_attribute = "類屬性"# 構(gòu)造方法(初始化對(duì)象時(shí)自動(dòng)調(diào)用)def __init__(self, param1, param2):# 實(shí)例屬性(屬于對(duì)象)self.attribute1 = param1  # 通過(guò)self綁定到對(duì)象self.attribute2 = param2# 實(shí)例方法(需通過(guò)對(duì)象調(diào)用,第一個(gè)參數(shù)為self)def instance_method(self, arg):print(f"實(shí)例方法:{self.attribute1}, 參數(shù):{arg}")# 類方法(需裝飾器@classmethod,第一個(gè)參數(shù)為cls)@classmethoddef class_method(cls):print(f"類方法:{cls.class_attribute}")# 靜態(tài)方法(無(wú)需綁定類或?qū)ο?#xff0c;通過(guò)@staticmethod裝飾)@staticmethoddef static_method():print("靜態(tài)方法")

3、對(duì)象(實(shí)例)的創(chuàng)建與使用

1. 創(chuàng)建對(duì)象(實(shí)例化類)

obj = ClassName("值1", "值2")  # 調(diào)用__init__方法初始化對(duì)象

2. 訪問(wèn)屬性和方法

# 訪問(wèn)實(shí)例屬性
print(obj.attribute1)  # 輸出:值1# 調(diào)用實(shí)例方法
obj.instance_method("參數(shù)")  # 輸出:實(shí)例方法:值1, 參數(shù):參數(shù)# 訪問(wèn)類屬性(通過(guò)類或?qū)ο?#xff09;
print(ClassName.class_attribute)  # 輸出:類屬性
print(obj.class_attribute)        # 輸出:類屬性# 調(diào)用類方法和靜態(tài)方法(通過(guò)類調(diào)用)
ClassName.class_method()  # 輸出:類方法:類屬性
ClassName.static_method() # 輸出:靜態(tài)方法

4.關(guān)鍵概念解析

1.self?的作用

  • 實(shí)例方法的第一個(gè)參數(shù)必須是self,代表當(dāng)前對(duì)象本身。
  • 通過(guò)self可以訪問(wèn)對(duì)象的屬性和方法。
class Person:def __init__(self, name):self.name = name  # 將參數(shù)name賦值給對(duì)象的name屬性def say_hello(self):print(f"Hello, {self.name}!")  # 通過(guò)self訪問(wèn)對(duì)象的name屬性

2. 類屬性 vs 實(shí)例屬性

類屬性:屬于類本身,所有對(duì)象共享,通過(guò)類名直接訪問(wèn)。

class Dog:species = "犬科"  # 類屬性dog1 = Dog()
print(Dog.species)  # 輸出:犬科(通過(guò)類訪問(wèn))
print(dog1.species) # 輸出:犬科(通過(guò)對(duì)象訪問(wèn))

實(shí)例屬性:屬于每個(gè)對(duì)象,通過(guò)self在構(gòu)造方法中定義,每個(gè)對(duì)象獨(dú)立存在。

class Dog:def __init__(self, name):self.name = name  # 實(shí)例屬性(每個(gè)狗的名字不同)dog1 = Dog("旺財(cái)")
dog2 = Dog("小白")
print(dog1.name)  # 輸出:旺財(cái)
print(dog2.name)  # 輸出:小白

3. 方法類型

方法類型裝飾器參數(shù)特點(diǎn)訪問(wèn)方式
實(shí)例方法無(wú)第一個(gè)參數(shù)為 self通過(guò)對(duì)象調(diào)用
類方法@classmethod第一個(gè)參數(shù)為 cls通過(guò)類調(diào)用
靜態(tài)方法@staticmethod無(wú)特殊參數(shù)通過(guò)類調(diào)用

5. 示例:定義 “學(xué)生” 類

class Student:# 類屬性:所有學(xué)生共享的學(xué)校名稱school = "XX中學(xué)"# 構(gòu)造方法:初始化學(xué)生的姓名和年級(jí)def __init__(self, name, grade):self.name = name    # 實(shí)例屬性:姓名self.grade = grade  # 實(shí)例屬性:年級(jí)# 實(shí)例方法:打印學(xué)生信息def show_info(self):print(f"姓名:{self.name},年級(jí):{self.grade},學(xué)校:{self.school}")# 類方法:修改學(xué)校名稱@classmethoddef change_school(cls, new_school):cls.school = new_school# 靜態(tài)方法:判斷是否為高年級(jí)(示例邏輯)@staticmethoddef is_senior(grade):return grade >= 3  # 假設(shè)3年級(jí)及以上為高年級(jí)# 創(chuàng)建學(xué)生對(duì)象
stu1 = Student("張三", 2)
stu2 = Student("李四", 4)# 調(diào)用實(shí)例方法
stu1.show_info()  # 輸出:姓名:張三,年級(jí):2,學(xué)校:XX中學(xué)
stu2.show_info()  # 輸出:姓名:李四,年級(jí):4,學(xué)校:XX中學(xué)# 調(diào)用類方法修改學(xué)校名稱
Student.change_school("實(shí)驗(yàn)中學(xué)")
print(Student.school)  # 輸出:實(shí)驗(yàn)中學(xué)# 調(diào)用靜態(tài)方法
print(Student.is_senior(3))  # 輸出:True

二. 繼承和多態(tài)

2.1繼承(Inheritance)

繼承是面向?qū)ο缶幊痰暮诵母拍钪?#xff0c;允許一個(gè)類(子類)繼承另一個(gè)類(父類)的屬性和方法,實(shí)現(xiàn)代碼復(fù)用和層次化設(shè)計(jì)。

1. 基本語(yǔ)法與概念

class ParentClass:def parent_method(self):print("這是父類的方法")class ChildClass(ParentClass):  # 子類繼承父類def child_method(self):print("這是子類的方法")# 創(chuàng)建子類對(duì)象
child = ChildClass()
child.parent_method()  # 調(diào)用父類方法
child.child_method()   # 調(diào)用子類方法

關(guān)鍵點(diǎn)

  • 子類通過(guò)括號(hào)內(nèi)指定父類名稱實(shí)現(xiàn)繼承。
  • 子類自動(dòng)獲得父類的所有非私有屬性和方法。
  • 子類可新增自己的屬性和方法,或重寫父類方法。

2. 方法重寫(Override)

子類可重新定義父類的方法,覆蓋其實(shí)現(xiàn):

class Animal:def speak(self):return "動(dòng)物發(fā)出聲音"class Dog(Animal):def speak(self):  # 重寫父類方法return "汪汪汪"class Cat(Animal):def speak(self):  # 重寫父類方法return "喵喵喵"# 測(cè)試
dog = Dog()
cat = Cat()
print(dog.speak())  # 輸出:汪汪汪
print(cat.speak())  # 輸出:喵喵喵

3. 多重繼承

Python 支持一個(gè)子類繼承多個(gè)父類:

class A:def method_a(self):print("A類的方法")class B:def method_b(self):print("B類的方法")class C(A, B):  # 繼承自A和Bpassc = C()
c.method_a()  # 輸出:A類的方法
c.method_b()  # 輸出:B類的方法

注意:多重繼承可能導(dǎo)致 “菱形繼承問(wèn)題”,需通過(guò) MRO(方法解析順序)解決。

4. 訪問(wèn)父類方法

通過(guò)super()調(diào)用父類的方法:

class Parent:def greet(self):print("Hello from Parent")class Child(Parent):def greet(self):super().greet()  # 調(diào)用父類的greet方法print("Hello from Child")child = Child()
child.greet()
# 輸出:
# Hello from Parent
# Hello from Child

2.2 多態(tài)(Polymorphism)

多態(tài)允許不同類的對(duì)象對(duì)同一方法做出不同響應(yīng),提高代碼靈活性和可擴(kuò)展性。

1. 基于繼承的多態(tài)

通過(guò)方法重寫實(shí)現(xiàn):

class Shape:def area(self):return 0  # 默認(rèn)實(shí)現(xiàn)class Rectangle(Shape):def __init__(self, width, height):self.width = widthself.height = heightdef area(self):  # 重寫area方法return self.width * self.heightclass Circle(Shape):def __init__(self, radius):self.radius = radiusdef area(self):  # 重寫area方法return 3.14 * self.radius ** 2# 多態(tài)調(diào)用
shapes = [Rectangle(2, 3), Circle(5)]
for shape in shapes:print(f"面積: {shape.area()}")  # 自動(dòng)調(diào)用對(duì)應(yīng)子類的area方法

2. 鴨子類型(Duck Typing)

Python 的多態(tài)不依賴?yán)^承,只要對(duì)象具有相同方法即可調(diào)用:

class Dog:def speak(self):return "汪汪汪"class Cat:def speak(self):return "喵喵喵"class Car:def speak(self):  # 不繼承任何類,但有相同方法名return "嘟嘟嘟"# 多態(tài)調(diào)用
def animal_speak(obj):print(obj.speak())dog = Dog()
cat = Cat()
car = Car()animal_speak(dog)  # 輸出:汪汪汪
animal_speak(cat)  # 輸出:喵喵喵
animal_speak(car)  # 輸出:嘟嘟嘟(Car類與動(dòng)物無(wú)關(guān),但仍可調(diào)用)

3. 抽象基類(Abstract Base Class)

強(qiáng)制子類實(shí)現(xiàn)特定方法:

from abc import ABC, abstractmethodclass Animal(ABC):  # 抽象基類@abstractmethod  # 抽象方法,子類必須實(shí)現(xiàn)def speak(self):passclass Dog(Animal):def speak(self):  # 實(shí)現(xiàn)抽象方法return "汪汪汪"class Cat(Animal):def speak(self):  # 實(shí)現(xiàn)抽象方法return "喵喵喵"# 無(wú)法實(shí)例化抽象基類
# animal = Animal()  # 報(bào)錯(cuò):TypeError# 合法的子類實(shí)例
dog = Dog()
print(dog.speak())  # 輸出:汪汪汪

4.代碼示例:員工管理系統(tǒng)

from abc import ABC, abstractmethodclass Employee(ABC):  # 抽象基類def __init__(self, name, salary):self.name = nameself.salary = salary@abstractmethoddef calculate_bonus(self):passdef get_info(self):return f"姓名: {self.name}, 工資: {self.salary}, 獎(jiǎng)金: {self.calculate_bonus()}"class FullTimeEmployee(Employee):def calculate_bonus(self):  # 實(shí)現(xiàn)抽象方法return self.salary * 0.2  # 20%獎(jiǎng)金class PartTimeEmployee(Employee):def calculate_bonus(self):  # 實(shí)現(xiàn)抽象方法return self.salary * 0.1  # 10%獎(jiǎng)金# 多態(tài)調(diào)用
employees = [FullTimeEmployee("張三", 8000),PartTimeEmployee("李四", 3000)
]for emp in employees:print(emp.get_info())  # 自動(dòng)調(diào)用對(duì)應(yīng)子類的calculate_bonus方法# 輸出:
# 姓名: 張三, 工資: 8000, 獎(jiǎng)金: 1600.0
# 姓名: 李四, 工資: 3000, 獎(jiǎng)金: 300.0

5. 繼承與多態(tài)的優(yōu)勢(shì)

  1. 代碼復(fù)用:通過(guò)繼承減少重復(fù)代碼。
  2. 可擴(kuò)展性:新增子類不影響現(xiàn)有代碼(開(kāi)閉原則)。
  3. 靈活性:通過(guò)多態(tài)統(tǒng)一接口,不同實(shí)現(xiàn)動(dòng)態(tài)切換。
  4. 可維護(hù)性:通過(guò)抽象基類明確接口規(guī)范,降低耦合度。

三. 特殊方法(魔術(shù)方法)

3.1、什么是特殊方法?

????????特殊方法(Magic Methods)也稱為魔術(shù)方法,是 Python 中預(yù)定義的、以雙下劃線(__)開(kāi)頭和結(jié)尾的方法。它們用于實(shí)現(xiàn)類的內(nèi)置行為(如初始化、運(yùn)算符重載、迭代等),無(wú)需顯式調(diào)用,而是由特定語(yǔ)法或內(nèi)置函數(shù)觸發(fā)。

常見(jiàn)用途

  • 對(duì)象初始化(__init__
  • 字符串表示(__str__,?__repr__
  • 算術(shù)運(yùn)算符(__add__,?__sub__
  • 比較運(yùn)算符(__eq__,?__lt__
  • 容器操作(__len__,?__getitem__
  • 上下文管理器(__enter__,?__exit__

3.2、常用特殊方法分類

1. 對(duì)象創(chuàng)建與銷毀

  • __init__(self, ...):初始化對(duì)象,創(chuàng)建實(shí)例時(shí)自動(dòng)調(diào)用。
  • __new__(cls, ...):創(chuàng)建對(duì)象實(shí)例的靜態(tài)方法,先于__init__執(zhí)行。
  • __del__(self):對(duì)象被垃圾回收時(shí)調(diào)用。

示例

class Person:def __init__(self, name, age):self.name = nameself.age = ageprint(f"創(chuàng)建了{(lán)self.name}")def __del__(self):print(f"銷毀了{(lán)self.name}")p = Person("張三", 20)  # 輸出:創(chuàng)建了張三
del p                  # 輸出:銷毀了張三

2. 字符串表示

  • __str__(self):返回對(duì)象的用戶友好字符串表示(str(obj)print(obj)時(shí)調(diào)用)。
  • __repr__(self):返回對(duì)象的開(kāi)發(fā)者友好字符串表示(交互式環(huán)境或repr(obj)時(shí)調(diào)用)。

示例

class Point:def __init__(self, x, y):self.x = xself.y = ydef __str__(self):return f"({self.x}, {self.y})"def __repr__(self):return f"Point({self.x}, {self.y})"p = Point(3, 4)
print(p)        # 輸出:(3, 4)(調(diào)用__str__)
print(repr(p))  # 輸出:Point(3, 4)(調(diào)用__repr__)

3. 算術(shù)運(yùn)算符重載

  • __add__(self, other):定義加法(+)行為。
  • __sub__(self, other):定義減法(-)行為。
  • __mul__(self, other):定義乘法(*)行為。
  • __truediv__(self, other):定義除法(/)行為。
  • __floordiv__(self, other):定義整除(//)行為。

示例

class Vector:def __init__(self, x, y):self.x = xself.y = ydef __add__(self, other):return Vector(self.x + other.x, self.y + other.y)def __str__(self):return f"Vector({self.x}, {self.y})"v1 = Vector(1, 2)
v2 = Vector(3, 4)
v3 = v1 + v2  # 調(diào)用__add__
print(v3)     # 輸出:Vector(4, 6)

4. 比較運(yùn)算符重載

  • __eq__(self, other):定義等于(==)行為。
  • __ne__(self, other):定義不等于(!=)行為。
  • __lt__(self, other):定義小于(<)行為。
  • __gt__(self, other):定義大于(>)行為。

示例

class Person:def __init__(self, age):self.age = agedef __eq__(self, other):return self.age == other.agedef __lt__(self, other):return self.age < other.agep1 = Person(20)
p2 = Person(25)
print(p1 == p2)  # 輸出:False(調(diào)用__eq__)
print(p1 < p2)   # 輸出:True(調(diào)用__lt__)

5. 容器類方法

  • __len__(self):返回容器長(zhǎng)度(len(obj)時(shí)調(diào)用)。
  • __getitem__(self, key):獲取容器元素(obj[key]時(shí)調(diào)用)。
  • __setitem__(self, key, value):設(shè)置容器元素(obj[key] = value時(shí)調(diào)用)。
  • __contains__(self, item):判斷元素是否存在(item in obj時(shí)調(diào)用)。

示例

class MyList:def __init__(self, *items):self.items = list(items)def __len__(self):return len(self.items)def __getitem__(self, index):return self.items[index]my_list = MyList(1, 2, 3)
print(len(my_list))      # 輸出:3(調(diào)用__len__)
print(my_list[1])        # 輸出:2(調(diào)用__getitem__)

6. 上下文管理器(with 語(yǔ)句)

  • __enter__(self):進(jìn)入上下文時(shí)調(diào)用,返回值綁定到as后的變量。
  • __exit__(self, exc_type, exc_value, traceback):退出上下文時(shí)調(diào)用,處理異常。

示例

class FileHandler:def __init__(self, filename, mode):self.filename = filenameself.mode = modedef __enter__(self):self.file = open(self.filename, self.mode)return self.filedef __exit__(self, exc_type, exc_value, traceback):self.file.close()return True  # 異常已處理,不再傳播with FileHandler("test.txt", "w") as f:f.write("Hello, World!")  # 自動(dòng)調(diào)用__enter__和__exit__

3.3、自定義類的特殊方法實(shí)戰(zhàn)

下面是一個(gè)綜合示例,展示如何通過(guò)特殊方法創(chuàng)建一個(gè)支持多種操作的自定義類:

class MyNumber:def __init__(self, value):self.value = value# 算術(shù)運(yùn)算def __add__(self, other):return MyNumber(self.value + other.value)def __sub__(self, other):return MyNumber(self.value - other.value)# 比較運(yùn)算def __eq__(self, other):return self.value == other.valuedef __gt__(self, other):return self.value > other.value# 字符串表示def __str__(self):return f"數(shù)值: {self.value}"def __repr__(self):return f"MyNumber({self.value})"# 類型轉(zhuǎn)換def __int__(self):return int(self.value)def __float__(self):return float(self.value)# 使用示例
a = MyNumber(5)
b = MyNumber(10)# 算術(shù)運(yùn)算
c = a + b
print(c)  # 輸出:數(shù)值: 15# 比較運(yùn)算
print(a > b)  # 輸出:False
print(a == b) # 輸出:False# 類型轉(zhuǎn)換
print(int(a))  # 輸出:5
print(float(a))  # 輸出:5.0

3.4、特殊方法總結(jié)

????????特殊方法是 Python 面向?qū)ο缶幊痰膹?qiáng)大工具,通過(guò)合理實(shí)現(xiàn)這些方法,可以讓自定義類具有與內(nèi)置類型相似的行為,提高代碼的可讀性和可維護(hù)性。

常見(jiàn)用途總結(jié)

類別常用方法
對(duì)象創(chuàng)建 / 銷毀__init__,?__new__,?__del__
字符串表示__str__,?__repr__
算術(shù)運(yùn)算符__add__,?__sub__,?__mul__
比較運(yùn)算符__eq__,?__lt__,?__gt__
容器操作__len__,?__getitem__
上下文管理器__enter__,?__exit__
類型轉(zhuǎn)換__int__,?__float__

????????通過(guò)深入理解和使用特殊方法,可以編寫出更加 Pythonic、靈活且高效的代碼。

四. 描述符和屬性

4.1、描述符(Descriptor)

????????描述符是一種實(shí)現(xiàn)了特定協(xié)議(__get____set__、__delete__)的類,用于控制類中屬性的訪問(wèn)行為。它是 Python 實(shí)現(xiàn)@property、classmethodstaticmethod等功能的底層機(jī)制,也是自定義屬性邏輯的強(qiáng)大工具。

1. 描述符協(xié)議的三個(gè)方法

方法名稱觸發(fā)時(shí)機(jī)參數(shù)說(shuō)明
__get__(self, instance, owner)當(dāng)訪問(wèn)屬性時(shí)調(diào)用instance:對(duì)象實(shí)例(若無(wú)則為None
owner:所屬類
__set__(self, instance, value)當(dāng)設(shè)置屬性值時(shí)調(diào)用instance:對(duì)象實(shí)例
value:要設(shè)置的值
__delete__(self, instance)當(dāng)刪除屬性時(shí)調(diào)用instance:對(duì)象實(shí)例

2. 描述符的類型

根據(jù)是否實(shí)現(xiàn)__set__方法,描述符分為兩類:

  • 數(shù)據(jù)描述符(Data Descriptor):實(shí)現(xiàn)了__set____get__,可完全控制屬性的讀寫。
  • 非數(shù)據(jù)描述符(Non-Data Descriptor):僅實(shí)現(xiàn)__get__,屬性為只讀(如@property裝飾的方法)。

3. 數(shù)據(jù)描述符示例:限制屬性類型

class TypedAttribute:def __init__(self, expected_type):self.expected_type = expected_typeself.name = None  # 存儲(chǔ)屬性名(通過(guò)__set_name__綁定)def __set_name__(self, owner, name):"""在類定義時(shí)自動(dòng)調(diào)用,綁定屬性名"""self.name = namedef __get__(self, instance, owner):"""獲取屬性值"""if instance is None:return self  # 通過(guò)類訪問(wèn)描述符時(shí)返回自身return instance.__dict__[self.name]  # 從實(shí)例字典獲取值def __set__(self, instance, value):"""設(shè)置屬性值,校驗(yàn)類型"""if not isinstance(value, self.expected_type):raise TypeError(f"{self.name}必須是{self.expected_type.__name__}類型")instance.__dict__[self.name] = value  # 存儲(chǔ)到實(shí)例字典# 使用描述符的類
class Person:name = TypedAttribute(str)   # 數(shù)據(jù)描述符:限制為str類型age = TypedAttribute(int)    # 數(shù)據(jù)描述符:限制為int類型# 測(cè)試
p = Person()
p.name = "張三"    # 合法
# p.age = "20"     # 報(bào)錯(cuò):TypeError: age必須是int類型

4. 非數(shù)據(jù)描述符示例:只讀屬性

class ReadOnlyDescriptor:def __init__(self, value):self.value = valuedef __get__(self, instance, owner):return self.valueclass Config:VERSION = ReadOnlyDescriptor("1.0.0")  # 非數(shù)據(jù)描述符:只讀print(Config.VERSION)  # 輸出:1.0.0
# Config.VERSION = "2.0.0"  # 報(bào)錯(cuò):AttributeError(無(wú)__set__方法)

5. 描述符的優(yōu)先級(jí)

描述符在類中的優(yōu)先級(jí)由以下規(guī)則決定(從高到低):

  1. 實(shí)例字典(__dict__:實(shí)例直接賦值的屬性會(huì)覆蓋描述符。
    p.name = "李四"  # 直接修改實(shí)例字典,繞過(guò)描述符的__set__
    
  2. 數(shù)據(jù)描述符:優(yōu)先于實(shí)例字典。
  3. 非數(shù)據(jù)描述符:低于實(shí)例字典。
  4. 普通屬性:無(wú)描述符時(shí),直接訪問(wèn)實(shí)例字典。

4.2、屬性(Property)

????????**@property** 是 Python 提供的語(yǔ)法糖,用于將類中的方法轉(zhuǎn)換為 “屬性”,簡(jiǎn)化數(shù)據(jù)描述符的使用。它本質(zhì)上是一個(gè)非數(shù)據(jù)描述符。

1.?@property基礎(chǔ)用法

class Circle:def __init__(self, radius):self._radius = radius  # 私有屬性,通過(guò)property訪問(wèn)@propertydef radius(self):"""獲取半徑(屬性 getter)"""return self._radius@radius.setterdef radius(self, value):"""設(shè)置半徑(屬性 setter)"""if value < 0:raise ValueError("半徑不能為負(fù)數(shù)")self._radius = value@propertydef area(self):"""計(jì)算面積(只讀屬性)"""return 3.14 * self._radius ** 2# 使用示例
c = Circle(5)
print(c.radius)   # 輸出:5(調(diào)用@property)
c.radius = 6      # 調(diào)用@radius.setter
print(c.area)     # 輸出:113.04(只讀屬性)
# c.area = 100    # 報(bào)錯(cuò):AttributeError(無(wú)setter)

2.?property的參數(shù)形式

不使用裝飾器時(shí),可通過(guò)property(fget, fset, fdel, doc)創(chuàng)建屬性:

class Circle:def __init__(self, radius):self._radius = radiusdef get_radius(self):return self._radiusdef set_radius(self, value):if value < 0:raise ValueError("半徑不能為負(fù)數(shù)")self._radius = valueradius = property(get_radius, set_radius)  # 定義屬性area = property(lambda self: 3.14 * self._radius ** 2)  # 只讀屬性

3. 屬性的優(yōu)勢(shì)

  • 封裝性:隱藏屬性的存儲(chǔ)細(xì)節(jié),通過(guò)方法控制訪問(wèn)。
  • 驗(yàn)證邏輯:在setter中添加數(shù)據(jù)校驗(yàn)(如類型、范圍檢查)。
  • 計(jì)算屬性:動(dòng)態(tài)生成屬性值(如area無(wú)需存儲(chǔ),實(shí)時(shí)計(jì)算)。

4、描述符 vs 屬性

特性描述符屬性(@property
實(shí)現(xiàn)方式自定義類,實(shí)現(xiàn)協(xié)議方法裝飾器或property函數(shù)
靈活性高(可復(fù)用,支持多個(gè)屬性)低(每個(gè)屬性需單獨(dú)定義)
適用場(chǎng)景多個(gè)屬性共享相同邏輯(如類型校驗(yàn))單個(gè)屬性的讀寫控制
數(shù)據(jù)描述符 / 非數(shù)據(jù)描述符可自定義(實(shí)現(xiàn)__set__即數(shù)據(jù)描述符)非數(shù)據(jù)描述符(默認(rèn)只讀,需@setter才為數(shù)據(jù)描述符)

5、實(shí)戰(zhàn):用描述符實(shí)現(xiàn)緩存屬性

class CacheDescriptor:def __init__(self, func):self.func = funcself.cache = {}  # 緩存字典def __get__(self, instance, owner):if instance is None:return selfkey = id(instance)if key not in self.cache:self.cache[key] = self.func(instance)  # 首次調(diào)用時(shí)計(jì)算并緩存return self.cache[key]class HeavyCalculation:def __init__(self, data):self.data = data@CacheDescriptor  # 使用描述符裝飾方法def result(self):print("執(zhí)行耗時(shí)計(jì)算...")return sum(self.data) * 0.5  # 模擬耗時(shí)操作# 測(cè)試
obj1 = HeavyCalculation([1, 2, 3, 4, 5])
print(obj1.result)  # 輸出:執(zhí)行耗時(shí)計(jì)算... 7.5(首次計(jì)算)
print(obj1.result)  # 直接從緩存獲取,不重復(fù)計(jì)算

6、總結(jié)

  • 描述符是 Python 的高級(jí)特性,用于實(shí)現(xiàn)屬性的復(fù)雜控制邏輯,是@property、classmethod等的底層機(jī)制。
  • **@property** 是描述符的簡(jiǎn)化用法,適合單個(gè)屬性的讀寫控制,常用于數(shù)據(jù)驗(yàn)證和計(jì)算屬性。
  • 合理使用描述符和屬性,可以讓代碼更具封裝性和可維護(hù)性,避免直接操作屬性帶來(lái)的安全隱患。

????????理解描述符和屬性的工作原理,有助于深入掌握 Python 的面向?qū)ο缶幊?#xff0c;并在需要時(shí)實(shí)現(xiàn)高度定制化的屬性行為。

五. 靜態(tài)方法和類方法

5.1、基本概念

類型綁定對(duì)象裝飾器第一個(gè)參數(shù)調(diào)用方式
實(shí)例方法實(shí)例無(wú)self(實(shí)例本身)obj.method()
類方法@classmethodcls(類本身)Class.method()
靜態(tài)方法無(wú)@staticmethod無(wú)特殊參數(shù)Class.method()

5.2、靜態(tài)方法(Static Method)

靜態(tài)方法屬于類,但不綁定類或?qū)嵗?#xff0c;類似于普通函數(shù)。它不能訪問(wèn)類或?qū)嵗膶傩?#xff0c;僅用于執(zhí)行與類相關(guān)的獨(dú)立功能。

1. 定義與使用

class Calculator:@staticmethoddef add(a, b):return a + b@staticmethoddef multiply(a, b):return a * b# 調(diào)用方式
print(Calculator.add(3, 5))       # 輸出:8
print(Calculator.multiply(4, 2))  # 輸出:8# 也可通過(guò)實(shí)例調(diào)用(不推薦)
calc = Calculator()
print(calc.add(3, 5))  # 輸出:8(但實(shí)例狀態(tài)不會(huì)被使用)

2. 核心特點(diǎn)

  • 不依賴實(shí)例狀態(tài):無(wú)法訪問(wèn)或修改實(shí)例屬性。
  • 不依賴類狀態(tài):無(wú)法訪問(wèn)或修改類屬性(如類變量)。
  • 用途:封裝與類相關(guān)的工具函數(shù),提高代碼組織性。

5.3、類方法(Class Method)

類方法綁定到類而非實(shí)例,通過(guò)第一個(gè)參數(shù)cls訪問(wèn)類屬性和方法,常用于創(chuàng)建工廠方法或修改類狀態(tài)。

1. 定義與使用

class Person:count = 0  # 類變量:記錄實(shí)例數(shù)量def __init__(self, name):self.name = namePerson.count += 1@classmethoddef get_count(cls):"""獲取類的實(shí)例數(shù)量"""return cls.count@classmethoddef create_anonymous(cls):"""工廠方法:創(chuàng)建匿名實(shí)例"""return cls("匿名用戶")# 使用示例
p1 = Person("張三")
p2 = Person("李四")print(Person.get_count())        # 輸出:2(通過(guò)類調(diào)用)
print(p1.get_count())            # 輸出:2(通過(guò)實(shí)例調(diào)用,仍綁定類)anon = Person.create_anonymous()
print(anon.name)                 # 輸出:匿名用戶

2. 核心特點(diǎn)

  • 訪問(wèn)類屬性:通過(guò)cls參數(shù)訪問(wèn)類變量(如cls.count)。
  • 修改類狀態(tài):可修改類變量或調(diào)用其他類方法。
  • 工廠方法:創(chuàng)建實(shí)例的替代構(gòu)造函數(shù)(如create_anonymous)。

5.4、靜態(tài)方法 vs 類方法

特性靜態(tài)方法類方法
第一個(gè)參數(shù)無(wú)特殊參數(shù)cls(類本身)
訪問(wèn)類屬性? 無(wú)法直接訪問(wèn)? 通過(guò)cls訪問(wèn)
修改類狀態(tài)? 無(wú)法修改? 可修改類變量
工廠方法? 不適用? 常用于創(chuàng)建實(shí)例的替代方式
適用場(chǎng)景與類相關(guān)的工具函數(shù)(如驗(yàn)證、計(jì)算)與類狀態(tài)相關(guān)的操作(如計(jì)數(shù)器、工廠)

5.5、實(shí)戰(zhàn)對(duì)比

1. 靜態(tài)方法示例:日期驗(yàn)證工具

class Date:def __init__(self, year, month, day):self.year = yearself.month = monthself.day = day@staticmethoddef is_valid_date(date_str):"""驗(yàn)證日期字符串是否合法"""year, month, day = map(int, date_str.split('-'))return 1 <= month <= 12 and 1 <= day <= 31# 使用示例
print(Date.is_valid_date("2023-10-15"))  # 輸出:True
print(Date.is_valid_date("2023-13-40"))  # 輸出:False

2. 類方法示例:工廠模式

class Pizza:def __init__(self, ingredients):self.ingredients = ingredients@classmethoddef margherita(cls):"""創(chuàng)建瑪格麗特披薩(固定配料)"""return cls(["番茄", "馬蘇里拉芝士", "羅勒"])@classmethoddef pepperoni(cls):"""創(chuàng)建意式香腸披薩(固定配料)"""return cls(["番茄", "馬蘇里拉芝士", "香腸"])# 使用示例
m = Pizza.margherita()
p = Pizza.pepperoni()print(m.ingredients)  # 輸出:['番茄', '馬蘇里拉芝士', '羅勒']
print(p.ingredients)  # 輸出:['番茄', '馬蘇里拉芝士', '香腸']

5.6、常見(jiàn)問(wèn)題

1. 何時(shí)使用靜態(tài)方法?

  • 函數(shù)邏輯與類相關(guān),但不依賴類或?qū)嵗隣顟B(tài)(如工具函數(shù))。
  • 提高代碼可讀性,將工具函數(shù)封裝在類內(nèi)部。

2. 何時(shí)使用類方法?

  • 需要訪問(wèn)或修改類變量(如計(jì)數(shù)器、配置)。
  • 創(chuàng)建工廠方法,提供多種實(shí)例化方式。
  • 實(shí)現(xiàn)繼承時(shí),確保子類調(diào)用正確的類方法(cls會(huì)自動(dòng)綁定到子類)。

3. 能否通過(guò)實(shí)例調(diào)用類方法 / 靜態(tài)方法?

可以,但不推薦。雖然實(shí)例可以調(diào)用類方法和靜態(tài)方法,但它們的第一個(gè)參數(shù)仍綁定類(cls)或無(wú)特殊綁定,不會(huì)使用實(shí)例狀態(tài)。

5.7、總結(jié)

  • 靜態(tài)方法是類的工具函數(shù),不依賴類或?qū)嵗隣顟B(tài),用于封裝獨(dú)立功能。
  • 類方法綁定類,通過(guò)cls訪問(wèn)類屬性,常用于工廠方法或類狀態(tài)操作。
  • 合理使用兩者可提高代碼的組織性和可維護(hù)性,避免濫用全局函數(shù)。

理解靜態(tài)方法和類方法的區(qū)別,有助于設(shè)計(jì)更清晰、更符合面向?qū)ο笤瓌t的 Python 類.

六. 封裝和私有屬性

6.1、封裝的概念

????????封裝(Encapsulation)?是面向?qū)ο缶幊痰娜筇匦灾?#xff08;另外兩個(gè)是繼承和多態(tài)),它指的是將數(shù)據(jù)(屬性)和操作數(shù)據(jù)的方法(行為)捆綁在一起,并通過(guò)訪問(wèn)控制隱藏內(nèi)部實(shí)現(xiàn)細(xì)節(jié),僅對(duì)外提供必要的接口。

封裝的核心目標(biāo)

  • 數(shù)據(jù)保護(hù):防止外部直接修改內(nèi)部數(shù)據(jù),避免意外破壞。
  • 接口簡(jiǎn)化:隱藏復(fù)雜的內(nèi)部實(shí)現(xiàn),只暴露高層接口,降低使用難度。
  • 可維護(hù)性:內(nèi)部實(shí)現(xiàn)可以自由修改,只要接口不變,外部代碼不受影響。

6.2、Python 的私有屬性與方法

Python 通過(guò)命名約定和特殊語(yǔ)法實(shí)現(xiàn)封裝,而非強(qiáng)制訪問(wèn)控制。

1. 單下劃線(_):弱私有(約定)

  • 含義:表示 “私有”,但僅是約定,外部仍可訪問(wèn)。
  • 用途:提示開(kāi)發(fā)者該屬性或方法不建議直接使用,可能在未來(lái)版本中變化。

示例

class BankAccount:def __init__(self, balance):self._balance = balance  # 單下劃線表示私有屬性def deposit(self, amount):self._balance += amountdef _calculate_interest(self):  # 單下劃線表示私有方法return self._balance * 0.05# 外部仍可訪問(wèn),但不建議
account = BankAccount(1000)
print(account._balance)  # 輸出:1000(可以訪問(wèn),但違反約定)

2. 雙下劃線(__):名稱修飾(Name Mangling)

  • 含義:強(qiáng)制私有,Python 會(huì)自動(dòng)將其重命名為_類名__屬性名,外部無(wú)法直接訪問(wèn)。
  • 用途:防止子類意外覆蓋父類的屬性或方法。

示例

class Parent:def __init__(self):self.__private_attr = 42  # 雙下劃線屬性def __private_method(self):  # 雙下劃線方法return "私有方法"class Child(Parent):passp = Parent()
print(p._Parent__private_attr)  # 輸出:42(通過(guò)重命名后的名稱訪問(wèn))
# print(p.__private_attr)       # 報(bào)錯(cuò):AttributeErrorc = Child()
# print(c.__private_attr)       # 報(bào)錯(cuò):AttributeError(子類無(wú)法直接訪問(wèn))
3. 雙下劃線結(jié)尾(__):特殊方法(避免使用)
  • 含義:Python 的特殊方法(如__init__、__str__),用于實(shí)現(xiàn)特定協(xié)議。
  • 注意:自定義屬性或方法應(yīng)避免使用雙下劃線結(jié)尾,防止與 Python 內(nèi)置名稱沖突。

6.3、封裝的最佳實(shí)踐

1. 使用屬性(@property)控制訪問(wèn)

通過(guò)@property裝飾器實(shí)現(xiàn)對(duì)私有屬性的訪問(wèn)控制,隱藏內(nèi)部實(shí)現(xiàn):

class Person:def __init__(self, age):self._age = age  # 私有屬性@propertydef age(self):"""獲取年齡(只讀)"""return self._age@age.setterdef age(self, value):"""設(shè)置年齡,添加驗(yàn)證邏輯"""if value < 0:raise ValueError("年齡不能為負(fù)數(shù)")self._age = value# 使用示例
p = Person(25)
print(p.age)  # 輸出:25(通過(guò)@property訪問(wèn))
p.age = 30    # 通過(guò)@age.setter設(shè)置
# p.age = -5   # 報(bào)錯(cuò):ValueError

2. 封裝內(nèi)部實(shí)現(xiàn)細(xì)節(jié)

將不對(duì)外公開(kāi)的邏輯封裝為私有方法,只暴露高層接口:

class DataProcessor:def __init__(self, data):self._data = datadef process(self):"""公開(kāi)的處理接口"""self._clean_data()self._analyze_data()return self._generate_report()def _clean_data(self):  # 私有方法self._data = [x for x in self._data if x is not None]def _analyze_data(self):  # 私有方法self._stats = {"mean": sum(self._data) / len(self._data)}def _generate_report(self):  # 私有方法return f"分析結(jié)果:平均值 = {self._stats['mean']}"# 使用示例
processor = DataProcessor([1, 2, 3, None, 5])
print(processor.process())  # 輸出:分析結(jié)果:平均值 = 2.75

3. 防止子類意外覆蓋

使用雙下劃線方法避免子類覆蓋父類的核心邏輯:

class Base:def __init__(self):self.__initialize()  # 強(qiáng)制私有方法,子類無(wú)法覆蓋def __initialize(self):  # 雙下劃線方法print("初始化基類")class Sub(Base):def __initialize(self):  # 這是一個(gè)新方法,不會(huì)覆蓋父類的__initializeprint("初始化子類")  # 不會(huì)被調(diào)用s = Sub()  # 輸出:初始化基類

4、封裝的優(yōu)勢(shì)

  1. 數(shù)據(jù)安全:通過(guò)訪問(wèn)控制避免外部直接修改敏感數(shù)據(jù)。

    # 錯(cuò)誤示例:直接修改內(nèi)部狀態(tài)
    account.balance = -1000  # 可能導(dǎo)致賬戶余額異常# 正確示例:通過(guò)方法控制修改
    account.deposit(100)     # 經(jīng)過(guò)驗(yàn)證的操作
    
  2. 代碼可維護(hù)性:內(nèi)部實(shí)現(xiàn)可以自由修改,不影響外部調(diào)用。

    # 原實(shí)現(xiàn):直接存儲(chǔ)平均值
    self._mean = sum(data) / len(data)# 新實(shí)現(xiàn):改為動(dòng)態(tài)計(jì)算(接口不變)
    @property
    def mean(self):return sum(self._data) / len(self._data)
    
  3. 簡(jiǎn)化接口:隱藏復(fù)雜細(xì)節(jié),提供簡(jiǎn)潔的 API。

    # 用戶只需調(diào)用高層方法,無(wú)需關(guān)心內(nèi)部步驟
    processor.process()  # 而非手動(dòng)調(diào)用多個(gè)方法
    

5、常見(jiàn)誤區(qū)

  1. 過(guò)度使用雙下劃線

    • 雙下劃線主要用于防止子類覆蓋,而非完全禁止外部訪問(wèn)。
    • 大多數(shù)情況下,單下劃線約定已足夠。
  2. 認(rèn)為雙下劃線是 “真正私有”

    • Python 沒(méi)有真正的私有屬性,雙下劃線只是名稱修飾,仍可通過(guò)_類名__屬性名訪問(wèn)。
  3. 忽略屬性的驗(yàn)證邏輯

    • 直接使用公共屬性(如self.age)而不添加驗(yàn)證,可能導(dǎo)致數(shù)據(jù)不一致。

6、總結(jié)

  • 封裝是將數(shù)據(jù)和操作捆綁,并控制訪問(wèn)的機(jī)制,提高代碼安全性和可維護(hù)性。
  • 單下劃線(_?是約定的私有標(biāo)識(shí),提示外部不要直接訪問(wèn)。
  • 雙下劃線(__?通過(guò)名稱修飾實(shí)現(xiàn)更強(qiáng)的封裝,防止子類意外覆蓋。
  • 屬性(@property?是實(shí)現(xiàn)封裝的最佳方式,允許對(duì)屬性訪問(wèn)添加驗(yàn)證和邏輯。

合理使用封裝,能夠設(shè)計(jì)出更加健壯、靈活且易于維護(hù)的 Python 類。

七. 抽象基類

7.1、抽象基類的概念

????????抽象基類(ABC)?是一種特殊的類,它定義了一組必須被子類實(shí)現(xiàn)的方法(抽象方法),但自身不能被實(shí)例化。抽象基類用于強(qiáng)制子類遵循特定的接口規(guī)范,確保多態(tài)性的正確實(shí)現(xiàn),是 Python 實(shí)現(xiàn) “接口繼承” 的核心機(jī)制。

7.2、如何定義抽象基類

在 Python 中,通過(guò)abc模塊的ABC類和@abstractmethod裝飾器定義抽象基類和抽象方法:

from abc import ABC, abstractmethodclass Animal(ABC):  # 繼承自ABC@abstractmethod  # 標(biāo)記為抽象方法def speak(self):"""子類必須實(shí)現(xiàn)的方法"""pass@abstractmethoddef move(self):pass

關(guān)鍵點(diǎn)

  • 抽象基類必須繼承自abc.ABC。
  • 抽象方法使用@abstractmethod裝飾,子類必須實(shí)現(xiàn)這些方法,否則無(wú)法實(shí)例化。
  • 抽象基類可以包含具體方法(非抽象方法),供子類直接繼承。

7.3、強(qiáng)制子類實(shí)現(xiàn)接口

如果子類未實(shí)現(xiàn)抽象基類的所有抽象方法,實(shí)例化時(shí)會(huì)拋出TypeError

正確實(shí)現(xiàn)示例

class Dog(Animal):def speak(self):return "汪汪汪"def move(self):  # 實(shí)現(xiàn)move方法return "四條腿跑"dog = Dog()
print(dog.speak())  # 輸出:汪汪汪

7.4、抽象基類的具體方法

抽象基類可以提供默認(rèn)實(shí)現(xiàn)的具體方法,供子類繼承或重寫:

from abc import ABC, abstractmethodclass FileHandler(ABC):def __init__(self, filename):self.filename = filename@abstractmethoddef read(self):pass@abstractmethoddef write(self, data):passdef close(self):  # 具體方法(非抽象)print(f"關(guān)閉文件 {self.filename}")# 子類繼承并實(shí)現(xiàn)抽象方法
class TextFile(FileHandler):def read(self):with open(self.filename, 'r') as f:return f.read()def write(self, data):with open(self.filename, 'w') as f:f.write(data)txt = TextFile("test.txt")
txt.write("Hello, ABC!")
txt.close()  # 調(diào)用基類的close方法

7.5、抽象基類的應(yīng)用場(chǎng)景

1. 定義接口規(guī)范

確保不同子類遵循統(tǒng)一的方法命名和參數(shù)列表,例如定義 “支付接口”:

from abc import ABC, abstractmethodclass Payment(ABC):@abstractmethoddef pay(self, amount):"""支付指定金額"""passclass Alipay(Payment):def pay(self, amount):print(f"支付寶支付{amount}元")class WeChatPay(Payment):def pay(self, amount):print(f"微信支付{amount}元")# 多態(tài)調(diào)用
def make_payment(payment: Payment, amount):payment.pay(amount)make_payment(Alipay(), 100)  # 輸出:支付寶支付100元
make_payment(WeChatPay(), 200) # 輸出:微信支付200元

2. 類型檢查

使用isinstance()issubclass()判斷對(duì)象或類是否符合抽象基類的接口:

class VirtualPayment(Payment):  # 未實(shí)現(xiàn)pay方法(故意錯(cuò)誤)passprint(issubclass(Alipay, Payment))   # 輸出:True
print(isinstance(Alipay(), Payment)) # 輸出:True# 未實(shí)現(xiàn)抽象方法的類不被視為子類
print(issubclass(VirtualPayment, Payment))  # 輸出:False

3. 插件系統(tǒng)設(shè)計(jì)

允許動(dòng)態(tài)加載符合抽象基類接口的插件,提高系統(tǒng)擴(kuò)展性:

# 基類(插件接口)
class Plugin(ABC):@abstractmethoddef run(self):pass# 插件實(shí)現(xiàn)
class DataPlugin(Plugin):def run(self):print("數(shù)據(jù)處理插件運(yùn)行")# 插件管理器
class PluginManager:def __init__(self):self.plugins = []def add_plugin(self, plugin):if isinstance(plugin, Plugin):  # 檢查是否符合接口self.plugins.append(plugin)else:raise TypeError("插件必須實(shí)現(xiàn)Plugin接口")

7.6、抽象基類 vs 接口繼承

  • 抽象基類:通過(guò)abc模塊顯式定義,允許包含抽象方法和具體方法,子類需顯式繼承。
  • 鴨子類型(Duck Typing):不依賴?yán)^承,只要對(duì)象具有相同方法即視為符合接口(如 Python 的liststr都支持__len__方法)。

選擇建議

  • 需要強(qiáng)制子類實(shí)現(xiàn)接口時(shí),使用抽象基類。
  • 追求靈活性和簡(jiǎn)潔性時(shí),優(yōu)先使用鴨子類型(如len(obj)不關(guān)心obj是否繼承自某個(gè)基類)。

7.7、注意事項(xiàng)

  1. 抽象基類不能實(shí)例化

    animal = Animal()  # 報(bào)錯(cuò):TypeError: Can't instantiate abstract class Animal with abstract methods speak, move
    
  2. 子類可部分實(shí)現(xiàn)抽象方法

    • 若子類未實(shí)現(xiàn)所有抽象方法,則子類仍為抽象基類,無(wú)法實(shí)例化。
  3. 抽象方法可以有默認(rèn)實(shí)現(xiàn)

    class Animal(ABC):@abstractmethoddef speak(self):return "默認(rèn)聲音"  # 子類可選擇重寫或使用默認(rèn)
    

7.8、總結(jié)

  • 抽象基類是 Python 實(shí)現(xiàn)接口規(guī)范的重要工具,通過(guò)@abstractmethod強(qiáng)制子類實(shí)現(xiàn)特定方法。
  • 適用于需要嚴(yán)格控制子類接口的場(chǎng)景(如框架設(shè)計(jì)、插件系統(tǒng))。
  • 結(jié)合多態(tài)性,可實(shí)現(xiàn)統(tǒng)一接口調(diào)用不同實(shí)現(xiàn)的靈活架構(gòu)。

????????合理使用抽象基類,能夠提高代碼的可維護(hù)性和可擴(kuò)展性,避免因子類接口不一致導(dǎo)致的問(wèn)題。

八、裝飾器本質(zhì)

8.1、裝飾器本質(zhì)

????????在 Python 中,@staticmethod?和?@classmethod?是內(nèi)置的裝飾器類,用于修改方法的綁定行為。它們的本質(zhì)是將普通方法轉(zhuǎn)換為特殊的描述符(Descriptor)對(duì)象,從而改變方法的調(diào)用邏輯。

8.2、@staticmethod?的實(shí)現(xiàn)原理

1. 工作機(jī)制

? ? @staticmethod?將方法轉(zhuǎn)換為一個(gè)不綁定類或?qū)嵗?/strong>的函數(shù),調(diào)用時(shí)不會(huì)自動(dòng)傳遞任何參數(shù)(如?self?或?cls)。

示例代碼

class MyClass:@staticmethoddef static_method(x, y):return x + y# 等價(jià)于手動(dòng)實(shí)現(xiàn)
def static_method(x, y):return x + yclass MyClass:static_method = staticmethod(static_method)  # 使用staticmethod類包裝

2. 底層實(shí)現(xiàn)

???staticmethod?是一個(gè)描述符類,實(shí)現(xiàn)了?__get__?方法,返回原始函數(shù)本身:

class staticmethod:def __init__(self, func):self.func = funcdef __get__(self, instance, owner=None):return self.func  # 直接返回原始函數(shù),不綁定任何對(duì)象

調(diào)用過(guò)程

obj = MyClass()
obj.static_method(1, 2)  # 等價(jià)于調(diào)用 MyClass.static_method(1, 2)

8.3、@classmethod?的實(shí)現(xiàn)原理

1. 工作機(jī)制

@classmethod?將方法轉(zhuǎn)換為一個(gè)綁定到類的方法,調(diào)用時(shí)自動(dòng)傳遞類本身作為第一個(gè)參數(shù)(cls)。

示例代碼

class MyClass:@classmethoddef class_method(cls, x, y):return cls(x, y)  # 創(chuàng)建類的實(shí)例# 等價(jià)于手動(dòng)實(shí)現(xiàn)
def class_method(cls, x, y):return cls(x, y)class MyClass:class_method = classmethod(class_method)  # 使用classmethod類包裝

2. 底層實(shí)現(xiàn)

classmethod?也是一個(gè)描述符類,其?__get__?方法返回一個(gè)綁定了類的函數(shù):

調(diào)用過(guò)程

obj = MyClass()
obj.class_method(1, 2)  # 等價(jià)于調(diào)用 MyClass.class_method(MyClass, 1, 2)

8.4、對(duì)比與驗(yàn)證

1. 驗(yàn)證描述符行為

通過(guò)查看方法的類型驗(yàn)證它們是描述符:

class MyClass:def instance_method(self):pass@staticmethoddef static_method():pass@classmethoddef class_method(cls):passprint(type(MyClass.instance_method))  # <class 'function'>(普通函數(shù),是描述符)
print(type(MyClass.static_method))   # <class 'function'>(靜態(tài)方法,是描述符)
print(type(MyClass.class_method))    # <class 'method'>(類方法,已綁定)obj = MyClass()
print(type(obj.instance_method))     # <class 'method'>(實(shí)例方法,已綁定)
print(type(obj.static_method))       # <class 'function'>(靜態(tài)方法,未綁定)
print(type(obj.class_method))        # <class 'method'>(類方法,已綁定)

2. 手動(dòng)實(shí)現(xiàn)裝飾器

使用自定義描述符模擬?@classmethod?的行為:

class MyClassMethod:def __init__(self, func):self.func = funcdef __get__(self, instance, owner=None):if owner is None:owner = type(instance)def wrapper(*args, **kwargs):return self.func(owner, *args, **kwargs)return wrapper# 使用自定義裝飾器
class MyClass:@MyClassMethod  # 等價(jià)于 @classmethoddef create(cls, value):return cls(value)obj = MyClass.create(42)  # 自動(dòng)傳遞 MyClass 作為第一個(gè)參數(shù)

8.5、應(yīng)用場(chǎng)景與優(yōu)勢(shì)

1.?@staticmethod?的優(yōu)勢(shì)

  • 減少命名空間污染:將工具函數(shù)封裝在類內(nèi)部,避免全局函數(shù)。
  • 提高代碼內(nèi)聚性:相關(guān)功能集中在類中,便于維護(hù)。

示例1

class MathUtils:@staticmethoddef is_prime(n):if n < 2:return Falsefor i in range(2, int(n**0.5) + 1):if n % i == 0:return Falsereturn True

示例2

class StaticMethod:def __init__(self, func):self.func = func  # 存儲(chǔ)原始函數(shù)def __get__(self, instance, owner=None):"""描述符協(xié)議:返回原始函數(shù),不綁定任何對(duì)象"""return self.func  # 直接返回原始函數(shù),不傳遞self或cls

2.?@classmethod?的優(yōu)勢(shì)

  • 工廠方法:創(chuàng)建實(shí)例的替代構(gòu)造函數(shù)(如從配置文件創(chuàng)建)。
  • 修改類狀態(tài):直接操作類變量,不依賴實(shí)例。

示例1

class Person:count = 0def __init__(self, name):self.name = namePerson.count += 1@classmethoddef get_count(cls):return cls.count@classmethoddef create_from_dict(cls, data):return cls(data["name"])

示例2

class ClassMethod:def __init__(self, func):self.func = func  # 存儲(chǔ)原始函數(shù)def __get__(self, instance, owner=None):"""描述符協(xié)議:返回綁定類的方法"""if owner is None:owner = type(instance)def bound_method(*args, **kwargs):"""綁定類的方法,自動(dòng)將類作為第一個(gè)參數(shù)傳遞"""return self.func(owner, *args, **kwargs)return bound_method  # 返回綁定類的方法

8.6、總結(jié)

  • @staticmethod?通過(guò)描述符機(jī)制將方法轉(zhuǎn)換為普通函數(shù),調(diào)用時(shí)不傳遞任何隱式參數(shù)。
  • @classmethod?通過(guò)描述符機(jī)制將方法綁定到類,調(diào)用時(shí)自動(dòng)傳遞類作為第一個(gè)參數(shù)。
  • 兩者本質(zhì)上都是通過(guò)描述符(Descriptor)協(xié)議實(shí)現(xiàn)的,是 Python 元編程的基礎(chǔ)工具之一。

8.6.?@property的實(shí)現(xiàn)原理

1、@property?的本質(zhì)

? @property?是 Python 內(nèi)置的數(shù)據(jù)描述符,用于將方法轉(zhuǎn)換為可像屬性一樣訪問(wèn)的特殊對(duì)象。它允許定義只讀屬性、讀寫屬性刪除屬性,并在訪問(wèn)時(shí)自動(dòng)執(zhí)行相應(yīng)的方法。

核心功能

  • 攔截屬性的訪問(wèn)(getter)、設(shè)置(setter)和刪除(deleter)操作。
  • 隱藏內(nèi)部實(shí)現(xiàn)細(xì)節(jié),提供簡(jiǎn)潔的屬性接口。

2、描述符協(xié)議與?@property

@property?的實(shí)現(xiàn)基于描述符協(xié)議的三個(gè)核心方法:

  • __get__(self, instance, owner):獲取屬性值時(shí)調(diào)用。
  • __set__(self, instance, value):設(shè)置屬性值時(shí)調(diào)用。
  • __delete__(self, instance):刪除屬性時(shí)調(diào)用。

簡(jiǎn)化版?property?描述符實(shí)現(xiàn)

class Property:def __init__(self, fget=None, fset=None, fdel=None, doc=None):self.fget = fget  # 獲取屬性的方法self.fset = fset  # 設(shè)置屬性的方法self.fdel = fdel  # 刪除屬性的方法self.__doc__ = doc  # 文檔字符串def __get__(self, instance, owner=None):if instance is None:return self  # 通過(guò)類訪問(wèn)時(shí)返回描述符本身if self.fget is None:raise AttributeError("屬性不可讀")return self.fget(instance)  # 調(diào)用獲取方法,傳遞實(shí)例def __set__(self, instance, value):if self.fset is None:raise AttributeError("屬性不可寫")self.fset(instance, value)  # 調(diào)用設(shè)置方法,傳遞實(shí)例和值def __delete__(self, instance):if self.fdel is None:raise AttributeError("屬性不可刪除")self.fdel(instance)  # 調(diào)用刪除方法,傳遞實(shí)例def getter(self, fget):"""創(chuàng)建一個(gè)新的property實(shí)例,更新fget方法"""return type(self)(fget, self.fset, self.fdel, self.__doc__)def setter(self, fset):"""創(chuàng)建一個(gè)新的property實(shí)例,更新fset方法"""return type(self)(self.fget, fset, self.fdel, self.__doc__)def deleter(self, fdel):"""創(chuàng)建一個(gè)新的property實(shí)例,更新fdel方法"""return type(self)(self.fget, self.fset, fdel, self.__doc__)

3、@property?的工作流程

1. 基本用法
class Person:def __init__(self, age):self._age = age  # 私有屬性@propertydef age(self):"""獲取年齡的方法(getter)"""return self._age@age.setterdef age(self, value):"""設(shè)置年齡的方法(setter)"""if value < 0:raise ValueError("年齡不能為負(fù)數(shù)")self._age = value
2. 等價(jià)的手動(dòng)實(shí)現(xiàn)
class Person:def __init__(self, age):self._age = agedef get_age(self):return self._agedef set_age(self, value):if value < 0:raise ValueError("年齡不能為負(fù)數(shù)")self._age = value# 使用自定義Property描述符age = Property(get_age, set_age)

4、描述符如何攔截屬性訪問(wèn)

????????當(dāng)通過(guò)實(shí)例訪問(wèn)被?@property?裝飾的屬性時(shí),Python 會(huì)自動(dòng)觸發(fā)描述符的?__get__、__set__?或?__delete__?方法:

1. 獲取屬性
p = Person(25)
print(p.age)  # 觸發(fā) Property.__get__(p, Person)
2. 設(shè)置屬性
p.age = 30  # 觸發(fā) Property.__set__(p, 30)
3. 刪除屬性
del p.age  # 觸發(fā) Property.__delete__(p)

5、驗(yàn)證描述符行為

通過(guò)自定義描述符驗(yàn)證?@property?的行為:

class DebugProperty:def __init__(self, fget=None):self.fget = fgetdef __get__(self, instance, owner=None):print(f"獲取屬性(instance={instance}, owner={owner})")return self.fget(instance) if instance else selfdef setter(self, fset):self.fset = fsetreturn selfdef __set__(self, instance, value):print(f"設(shè)置屬性為 {value}")if not hasattr(self, 'fset'):raise AttributeError("屬性不可寫")self.fset(instance, value)# 使用自定義描述符
class Circle:def __init__(self, radius):self._radius = radius@DebugProperty  # 等價(jià)于@propertydef radius(self):return self._radius@radius.setterdef radius(self, value):self._radius = value# 驗(yàn)證
c = Circle(5)
print(c.radius)  # 輸出:獲取屬性(instance=<__main__.Circle object...>, owner=<class '__main__.Circle'>) 5
c.radius = 10    # 輸出:設(shè)置屬性為 10

6、@property?的優(yōu)勢(shì)

  1. 接口一致性:通過(guò)屬性語(yǔ)法訪問(wèn),隱藏方法調(diào)用的復(fù)雜性。

    # 無(wú)@property
    print(p.get_age())  # 方法調(diào)用# 有@property
    print(p.age)        # 屬性訪問(wèn)
    
  2. 數(shù)據(jù)驗(yàn)證:在 setter 中添加邏輯,確保數(shù)據(jù)合法性。

    @age.setter
    def age(self, value):if value < 0:raise ValueError("年齡不能為負(fù)數(shù)")self._age = value
    
  3. 計(jì)算屬性:動(dòng)態(tài)生成屬性值,無(wú)需存儲(chǔ)中間結(jié)果。

    @property
    def area(self):return 3.14 * self._radius ** 2  # 每次訪問(wèn)時(shí)計(jì)算
    

7、總結(jié)

  • @property?是數(shù)據(jù)描述符:通過(guò)實(shí)現(xiàn)?__get____set__?和?__delete__?方法,攔截屬性的訪問(wèn)、設(shè)置和刪除操作。
  • 裝飾器語(yǔ)法糖@property?和?@attr.setter?實(shí)際上是創(chuàng)建和修改描述符實(shí)例的過(guò)程。
  • 描述符優(yōu)先級(jí):數(shù)據(jù)描述符(如?@property)的優(yōu)先級(jí)高于實(shí)例字典,確保屬性訪問(wèn)被正確攔截。

????????這些示例涵蓋了Python面向?qū)ο缶幊痰暮诵母拍?#xff0c;包括類定義、繼承、多態(tài)、特殊方法、屬性訪問(wèn)控制、靜態(tài)和類方法,以及抽象基類等。

http://aloenet.com.cn/news/43463.html

相關(guān)文章:

  • 做網(wǎng)站前微信朋友圈廣告如何投放
  • 快速搭建展示型網(wǎng)站b2b電子商務(wù)平臺(tái)網(wǎng)站
  • 客服外包在哪里接活長(zhǎng)沙seo代理
  • 外貿(mào)網(wǎng)站如何做seo谷歌seo課程
  • 政府網(wǎng)站集群的建設(shè)思路百度查重免費(fèi)入口
  • 長(zhǎng)沙企業(yè)100強(qiáng)名單福建seo關(guān)鍵詞優(yōu)化外包
  • 玉器哪家網(wǎng)站做的好個(gè)人網(wǎng)站備案
  • 順德專業(yè)網(wǎng)站制作友情鏈接分析
  • 一元注冊(cè)公司流程汕頭最好的seo外包
  • 昆明網(wǎng)站制作網(wǎng)頁(yè)環(huán)球軍事新聞最新消息
  • 網(wǎng)站建設(shè)需求調(diào)研計(jì)劃表網(wǎng)絡(luò)推廣的方法和技巧
  • 義烏網(wǎng)站優(yōu)化福建seo學(xué)校
  • 網(wǎng)站做提示框今日新聞50字
  • 域名鏈接網(wǎng)站網(wǎng)絡(luò)推廣都是收費(fèi)
  • 網(wǎng)站推廣文案谷歌商店下載
  • 網(wǎng)站設(shè)計(jì)建設(shè)公司seo原創(chuàng)工具
  • 沈陽(yáng)男科醫(yī)院哪家好醫(yī)關(guān)于進(jìn)一步優(yōu)化 廣州
  • 廣州網(wǎng)站制作系統(tǒng)優(yōu)化seo方法
  • 有免費(fèi)做網(wǎng)站的嗎北京網(wǎng)站優(yōu)化seo
  • 網(wǎng)站備案屬于公司哪一塊能讓手機(jī)流暢到爆的軟件
  • 鄭州網(wǎng)站開(kāi)發(fā)與建設(shè)長(zhǎng)沙網(wǎng)站優(yōu)化seo
  • 網(wǎng)站的banner輪播怎么做網(wǎng)站秒收錄
  • 公司網(wǎng)站的建設(shè)要注意什么臨沂百度推廣的電話
  • 百度驗(yàn)證網(wǎng)站seo優(yōu)化神器
  • 廣東新聞聯(lián)播吳姍姍seo服務(wù)深圳
  • 手機(jī)網(wǎng)站開(kāi)發(fā)用什么語(yǔ)言百度不讓訪問(wèn)危險(xiǎn)網(wǎng)站怎么辦
  • 婚戀網(wǎng)站翻譯可以做嗎中國(guó)數(shù)據(jù)統(tǒng)計(jì)網(wǎng)站
  • 通化網(wǎng)站制作濟(jì)南特大最新消息
  • 邵陽(yáng)市城鄉(xiāng)建設(shè)廳網(wǎng)站一鍵清理加速
  • 自己怎么做企業(yè)網(wǎng)站建設(shè)上海短視頻seo優(yōu)化網(wǎng)站