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

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

網(wǎng)站前端設(shè)計(jì)網(wǎng)絡(luò)營銷案例分析報告

網(wǎng)站前端設(shè)計(jì),網(wǎng)絡(luò)營銷案例分析報告,永康企業(yè)網(wǎng)站建設(shè),選擇莆田交友網(wǎng)站一、類和對象 1. 類和對象基礎(chǔ) 類(Class)的概念 類是對一類事物的抽象描述,定義了這類事物的屬性(數(shù)據(jù))和方法(行為)。 屬性:類的特征,如 “人” 的姓名、年齡。方法&am…

一、類和對象

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

類(Class)的概念

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

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

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

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

2、定義類的語法

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

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

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

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

2. 訪問屬性和方法

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

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

1.self?的作用

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

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

類屬性:屬于類本身,所有對象共享,通過類名直接訪問。

class Dog:species = "犬科"  # 類屬性dog1 = Dog()
print(Dog.species)  # 輸出:犬科(通過類訪問)
print(dog1.species) # 輸出:犬科(通過對象訪問)

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

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

3. 方法類型

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

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

class Student:# 類屬性:所有學(xué)生共享的學(xué)校名稱school = "XX中學(xué)"# 構(gòu)造方法:初始化學(xué)生的姓名和年級def __init__(self, name, grade):self.name = name    # 實(shí)例屬性:姓名self.grade = grade  # 實(shí)例屬性:年級# 實(shí)例方法:打印學(xué)生信息def show_info(self):print(f"姓名:{self.name},年級:{self.grade},學(xué)校:{self.school}")# 類方法:修改學(xué)校名稱@classmethoddef change_school(cls, new_school):cls.school = new_school# 靜態(tài)方法:判斷是否為高年級(示例邏輯)@staticmethoddef is_senior(grade):return grade >= 3  # 假設(shè)3年級及以上為高年級# 創(chuàng)建學(xué)生對象
stu1 = Student("張三", 2)
stu2 = Student("李四", 4)# 調(diào)用實(shí)例方法
stu1.show_info()  # 輸出:姓名:張三,年級:2,學(xué)校:XX中學(xué)
stu2.show_info()  # 輸出:姓名:李四,年級: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;允許一個類(子類)繼承另一個類(父類)的屬性和方法,實(shí)現(xiàn)代碼復(fù)用和層次化設(shè)計(jì)。

1. 基本語法與概念

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

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

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

2. 方法重寫(Override)

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

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

3. 多重繼承

Python 支持一個子類繼承多個父類:

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)致 “菱形繼承問題”,需通過 MRO(方法解析順序)解決。

4. 訪問父類方法

通過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)允許不同類的對象對同一方法做出不同響應(yīng),提高代碼靈活性和可擴(kuò)展性。

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

通過方法重寫實(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()}")  # 自動調(diào)用對應(yīng)子類的area方法

2. 鴨子類型(Duck Typing)

Python 的多態(tài)不依賴?yán)^承,只要對象具有相同方法即可調(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類與動物無關(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 "喵喵喵"# 無法實(shí)例化抽象基類
# animal = Animal()  # 報錯: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}, 獎金: {self.calculate_bonus()}"class FullTimeEmployee(Employee):def calculate_bonus(self):  # 實(shí)現(xiàn)抽象方法return self.salary * 0.2  # 20%獎金class PartTimeEmployee(Employee):def calculate_bonus(self):  # 實(shí)現(xiàn)抽象方法return self.salary * 0.1  # 10%獎金# 多態(tài)調(diào)用
employees = [FullTimeEmployee("張三", 8000),PartTimeEmployee("李四", 3000)
]for emp in employees:print(emp.get_info())  # 自動調(diào)用對應(yīng)子類的calculate_bonus方法# 輸出:
# 姓名: 張三, 工資: 8000, 獎金: 1600.0
# 姓名: 李四, 工資: 3000, 獎金: 300.0

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

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

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

3.1、什么是特殊方法?

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

常見用途

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

3.2、常用特殊方法分類

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

  • __init__(self, ...):初始化對象,創(chuàng)建實(shí)例時自動調(diào)用。
  • __new__(cls, ...):創(chuàng)建對象實(shí)例的靜態(tài)方法,先于__init__執(zhí)行。
  • __del__(self):對象被垃圾回收時調(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):返回對象的用戶友好字符串表示(str(obj)print(obj)時調(diào)用)。
  • __repr__(self):返回對象的開發(fā)者友好字符串表示(交互式環(huán)境或repr(obj)時調(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):返回容器長度(len(obj)時調(diào)用)。
  • __getitem__(self, key):獲取容器元素(obj[key]時調(diào)用)。
  • __setitem__(self, key, value):設(shè)置容器元素(obj[key] = value時調(diào)用)。
  • __contains__(self, item):判斷元素是否存在(item in obj時調(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 語句)

  • __enter__(self):進(jìn)入上下文時調(diào)用,返回值綁定到as后的變量。
  • __exit__(self, exc_type, exc_value, traceback):退出上下文時調(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!")  # 自動調(diào)用__enter__和__exit__

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

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

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)大工具,通過合理實(shí)現(xiàn)這些方法,可以讓自定義類具有與內(nèi)置類型相似的行為,提高代碼的可讀性和可維護(hù)性。

常見用途總結(jié)

類別常用方法
對象創(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__

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

四. 描述符和屬性

4.1、描述符(Descriptor)

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

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

方法名稱觸發(fā)時機(jī)參數(shù)說明
__get__(self, instance, owner)當(dāng)訪問屬性時調(diào)用instance:對象實(shí)例(若無則為None
owner:所屬類
__set__(self, instance, value)當(dāng)設(shè)置屬性值時調(diào)用instance:對象實(shí)例
value:要設(shè)置的值
__delete__(self, instance)當(dāng)刪除屬性時調(diào)用instance:對象實(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  # 存儲屬性名(通過__set_name__綁定)def __set_name__(self, owner, name):"""在類定義時自動調(diào)用,綁定屬性名"""self.name = namedef __get__(self, instance, owner):"""獲取屬性值"""if instance is None:return self  # 通過類訪問描述符時返回自身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  # 存儲到實(shí)例字典# 使用描述符的類
class Person:name = TypedAttribute(str)   # 數(shù)據(jù)描述符:限制為str類型age = TypedAttribute(int)    # 數(shù)據(jù)描述符:限制為int類型# 測試
p = Person()
p.name = "張三"    # 合法
# p.age = "20"     # 報錯: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"  # 報錯:AttributeError(無__set__方法)

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

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

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

4.2、屬性(Property)

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

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

class Circle:def __init__(self, radius):self._radius = radius  # 私有屬性,通過property訪問@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    # 報錯:AttributeError(無setter)

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

不使用裝飾器時,可通過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)勢

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

4、描述符 vs 屬性

特性描述符屬性(@property
實(shí)現(xiàn)方式自定義類,實(shí)現(xiàn)協(xié)議方法裝飾器或property函數(shù)
靈活性高(可復(fù)用,支持多個屬性)低(每個屬性需單獨(dú)定義)
適用場景多個屬性共享相同邏輯(如類型校驗(yàn))單個屬性的讀寫控制
數(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)用時計(jì)算并緩存return self.cache[key]class HeavyCalculation:def __init__(self, data):self.data = data@CacheDescriptor  # 使用描述符裝飾方法def result(self):print("執(zhí)行耗時計(jì)算...")return sum(self.data) * 0.5  # 模擬耗時操作# 測試
obj1 = HeavyCalculation([1, 2, 3, 4, 5])
print(obj1.result)  # 輸出:執(zhí)行耗時計(jì)算... 7.5(首次計(jì)算)
print(obj1.result)  # 直接從緩存獲取,不重復(fù)計(jì)算

6、總結(jié)

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

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

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

5.1、基本概念

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

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

靜態(tài)方法屬于類,但不綁定類或?qū)嵗?#xff0c;類似于普通函數(shù)。它不能訪問類或?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# 也可通過實(shí)例調(diào)用(不推薦)
calc = Calculator()
print(calc.add(3, 5))  # 輸出:8(但實(shí)例狀態(tài)不會被使用)

2. 核心特點(diǎn)

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

5.3、類方法(Class Method)

類方法綁定到類而非實(shí)例,通過第一個參數(shù)cls訪問類屬性和方法,常用于創(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(通過類調(diào)用)
print(p1.get_count())            # 輸出:2(通過實(shí)例調(diào)用,仍綁定類)anon = Person.create_anonymous()
print(anon.name)                 # 輸出:匿名用戶

2. 核心特點(diǎn)

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

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

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

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

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、常見問題

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

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

2. 何時使用類方法?

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

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

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

5.7、總結(jié)

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

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

六. 封裝和私有屬性

6.1、封裝的概念

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

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

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

6.2、Python 的私有屬性與方法

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

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

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

示例

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

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

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

示例

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(通過重命名后的名稱訪問)
# print(p.__private_attr)       # 報錯:AttributeErrorc = Child()
# print(c.__private_attr)       # 報錯:AttributeError(子類無法直接訪問)
3. 雙下劃線結(jié)尾(__):特殊方法(避免使用)
  • 含義:Python 的特殊方法(如__init__、__str__),用于實(shí)現(xiàn)特定協(xié)議。
  • 注意:自定義屬性或方法應(yīng)避免使用雙下劃線結(jié)尾,防止與 Python 內(nèi)置名稱沖突。

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

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

通過@property裝飾器實(shí)現(xià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(通過@property訪問)
p.age = 30    # 通過@age.setter設(shè)置
# p.age = -5   # 報錯:ValueError

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

將不對外公開的邏輯封裝為私有方法,只暴露高層接口:

class DataProcessor:def __init__(self, data):self._data = datadef process(self):"""公開的處理接口"""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)制私有方法,子類無法覆蓋def __initialize(self):  # 雙下劃線方法print("初始化基類")class Sub(Base):def __initialize(self):  # 這是一個新方法,不會覆蓋父類的__initializeprint("初始化子類")  # 不會被調(diào)用s = Sub()  # 輸出:初始化基類

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

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

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

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

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

5、常見誤區(qū)

  1. 過度使用雙下劃線

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

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

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

6、總結(jié)

  • 封裝是將數(shù)據(jù)和操作捆綁,并控制訪問的機(jī)制,提高代碼安全性和可維護(hù)性。
  • 單下劃線(_?是約定的私有標(biāo)識,提示外部不要直接訪問。
  • 雙下劃線(__?通過名稱修飾實(shí)現(xiàn)更強(qiáng)的封裝,防止子類意外覆蓋。
  • 屬性(@property?是實(shí)現(xià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 中,通過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)這些方法,否則無法實(shí)例化。
  • 抽象基類可以包含具體方法(非抽象方法),供子類直接繼承。

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

如果子類未實(shí)現(xiàn)抽象基類的所有抽象方法,實(shí)例化時會拋出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)用場景

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()判斷對象或類是否符合抽象基類的接口:

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

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

允許動態(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 接口繼承

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

選擇建議

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

7.7、注意事項(xiàng)

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

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

    • 若子類未實(shí)現(xiàn)所有抽象方法,則子類仍為抽象基類,無法實(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ī)范的重要工具,通過@abstractmethod強(qiáng)制子類實(shí)現(xiàn)特定方法。
  • 適用于需要嚴(yán)格控制子類接口的場景(如框架設(shè)計(jì)、插件系統(tǒng))。
  • 結(jié)合多態(tài)性,可實(shí)現(xiàn)統(tǒng)一接口調(diào)用不同實(shí)現(xiàn)的靈活架構(gòu)。

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

八、裝飾器本質(zhì)

8.1、裝飾器本質(zhì)

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

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

1. 工作機(jī)制

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

示例代碼

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

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

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

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

調(diào)用過程

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

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

1. 工作機(jī)制

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

示例代碼

class MyClass:@classmethoddef class_method(cls, x, y):return cls(x, y)  # 創(chuàng)建類的實(shí)例# 等價于手動實(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?也是一個描述符類,其?__get__?方法返回一個綁定了類的函數(shù):

調(diào)用過程

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

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

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

通過查看方法的類型驗(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. 手動實(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  # 等價于 @classmethoddef create(cls, value):return cls(value)obj = MyClass.create(42)  # 自動傳遞 MyClass 作為第一個參數(shù)

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

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

  • 減少命名空間污染:將工具函數(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  # 存儲原始函數(shù)def __get__(self, instance, owner=None):"""描述符協(xié)議:返回原始函數(shù),不綁定任何對象"""return self.func  # 直接返回原始函數(shù),不傳遞self或cls

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

  • 工廠方法:創(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  # 存儲原始函數(shù)def __get__(self, instance, owner=None):"""描述符協(xié)議:返回綁定類的方法"""if owner is None:owner = type(instance)def bound_method(*args, **kwargs):"""綁定類的方法,自動將類作為第一個參數(shù)傳遞"""return self.func(owner, *args, **kwargs)return bound_method  # 返回綁定類的方法

8.6、總結(jié)

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

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

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

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

核心功能

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

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

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

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

簡化版?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  # 通過類訪問時返回描述符本身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)建一個新的property實(shí)例,更新fget方法"""return type(self)(fget, self.fset, self.fdel, self.__doc__)def setter(self, fset):"""創(chuàng)建一個新的property實(shí)例,更新fset方法"""return type(self)(self.fget, fset, self.fdel, self.__doc__)def deleter(self, fdel):"""創(chuàng)建一個新的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. 等價的手動實(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、描述符如何攔截屬性訪問

????????當(dāng)通過實(shí)例訪問被?@property?裝飾的屬性時,Python 會自動觸發(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)證描述符行為

通過自定義描述符驗(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  # 等價于@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)勢

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

    # 無@property
    print(p.get_age())  # 方法調(diào)用# 有@property
    print(p.age)        # 屬性訪問
    
  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ì)算屬性:動態(tài)生成屬性值,無需存儲中間結(jié)果。

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

7、總結(jié)

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

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

http://m.aloenet.com.cn/news/32189.html

相關(guān)文章:

  • 福州網(wǎng)站制作案例石家莊百度快照優(yōu)化排名
  • 聊天app開發(fā)源碼搜索引擎優(yōu)化seo專員
  • 國外域名查詢網(wǎng)站2021年10月新聞?wù)?/a>
  • 屬于網(wǎng)頁制作平臺蘭州seo優(yōu)化
  • 合肥網(wǎng)站關(guān)鍵詞好網(wǎng)站
  • 3g網(wǎng)站開發(fā)怎么在百度上投放廣告
  • 動態(tài)網(wǎng)站開發(fā)語言優(yōu)勢需要留電話號碼的廣告
  • 阿里云企業(yè)網(wǎng)站備案制作網(wǎng)頁一般多少錢
  • 武漢企業(yè)宣傳片制作公司保定seo推廣外包
  • 深圳做網(wǎng)站設(shè)計(jì)公司營銷策略包括哪些內(nèi)容
  • 網(wǎng)站app開發(fā)建設(shè)關(guān)鍵詞在線查詢
  • 淳化網(wǎng)站制作福州網(wǎng)站快速排名提升
  • 胖咯科技網(wǎng)站建設(shè)百度小說風(fēng)云榜
  • 深圳住房建設(shè)廳網(wǎng)站首頁搜索量查詢
  • wordpress 刷新緩存太原百度關(guān)鍵詞優(yōu)化
  • 重復(fù)打開同一個網(wǎng)站怎么做軟文推廣多少錢
  • 技術(shù)支持 湖州網(wǎng)站建設(shè)百度怎么發(fā)布自己的信息
  • 泉州企業(yè)網(wǎng)站建設(shè)批量查詢指數(shù)
  • 自己有個服務(wù)器 怎樣做網(wǎng)站推廣普通話手抄報文字
  • 我們的網(wǎng)站長沙網(wǎng)站制作公司哪家好
  • 微信php網(wǎng)站開發(fā)流程人民網(wǎng) 疫情
  • 網(wǎng)絡(luò)工作室起名seo主管招聘
  • 學(xué)建網(wǎng)站 必須學(xué)那些知識seo網(wǎng)絡(luò)推廣優(yōu)化
  • 聊城網(wǎng)站建設(shè)上饒seo博客
  • 廣安市國土資源局網(wǎng)站建設(shè)推廣通
  • ps做網(wǎng)站主頁圖片怎樣在百度上免費(fèi)做廣告
  • 購物網(wǎng)站設(shè)計(jì)目的小吳seo博客
  • ssp網(wǎng)站怎么做最快新聞資訊在哪看
  • 云南房產(chǎn)網(wǎng)站建設(shè)seo基礎(chǔ)入門教程
  • jsp寫的網(wǎng)站營銷型網(wǎng)站建設(shè)運(yùn)營