h5如何做多頁(yè)面網(wǎng)站愛(ài)站查詢
文章目錄
- 類型:
- 數(shù)據(jù)描述符:
- 方法描述符:
- 描述符的要包括以下幾點(diǎn):
- 方法描述符
- 實(shí)現(xiàn)緩存
描述符(Descriptor)
是 Python 中一個(gè)非常強(qiáng)大的特性,它允許我們自定義屬性的訪問(wèn)行為。使用描述符,我們可以創(chuàng)建一些特殊的屬性,在訪問(wèn)這些屬性時(shí)執(zhí)行自定義的邏輯,如數(shù)據(jù)驗(yàn)證、屬性計(jì)算等。
類型:
**數(shù)據(jù)描述符:**用于修改屬性的訪問(wèn)和修改行為。
**方法描述符:**用于修改方法的行為。
數(shù)據(jù)描述符:
**get:**在屬性被訪問(wèn)時(shí)被調(diào)用。
**set:**在屬性被設(shè)置時(shí)被調(diào)用。
**delete:**在屬性被刪除時(shí)被調(diào)用。
方法描述符:
**call:**在方法被調(diào)用時(shí)被調(diào)用。
下面我們來(lái)看一個(gè)具體的例子:
class MyDescriptor:def __init__(self, initial_value=None):self._value = initial_valuedef __get__(self, instance, owner):print(f"Getting value: {self._value}")return self._valuedef __set__(self, instance, value):print(f"Setting value to: {value}")self._value = valuedef __delete__(self, instance):print("Deleting value")del self._valueclass MyClass:my_attr = MyDescriptor(42)obj = MyClass()
print(obj.my_attr) # Output: Getting value: 42
obj.my_attr = 100 # Output: Setting value to: 100
del obj.my_attr # Output: Deleting value
在這個(gè)例子中,我們定義了一個(gè) MyDescriptor
類,它實(shí)現(xiàn)了三個(gè)描述符協(xié)議方法:__get__
、__set__
和 __delete__
。這些方法分別在訪問(wèn)、設(shè)置和刪除屬性時(shí)被調(diào)用。
在 MyClass
中,我們定義了一個(gè) my_attr
屬性,它使用 MyDescriptor
作為描述符。當(dāng)我們?cè)L問(wèn)、設(shè)置或刪除 obj.my_attr
時(shí),相應(yīng)的描述符方法會(huì)被調(diào)用,并執(zhí)行我們自定義的邏輯。
描述符的要包括以下幾點(diǎn):
- 數(shù)據(jù)驗(yàn)證: 可以在
__set__
方法中添加數(shù)據(jù)驗(yàn)證邏輯,確保屬性值符合預(yù)期。 - 屬性計(jì)算: 在
__get__
方法中實(shí)現(xiàn)動(dòng)態(tài)計(jì)算屬性值的邏輯。 - 屬性緩存: 使用描述符可以實(shí)現(xiàn)屬性值的緩存,提高訪問(wèn)性能。
- 懶加載: 描述符可以用于實(shí)現(xiàn)懶加載,即在第一次訪問(wèn)屬性時(shí)才計(jì)算或加載屬性值。
- 屬性權(quán)限控制: 可以使用描述符實(shí)現(xiàn)只讀、只寫(xiě)或讀寫(xiě)屬性。
- 屬性依賴管理: 描述符可以用于管理屬性之間的依賴關(guān)系,確保屬性值的一致性。
下面是一個(gè)的代碼示例,實(shí)現(xiàn)了一個(gè)帶有數(shù)據(jù)驗(yàn)證和屬性緩存的描述符:
class CachedProperty:def __init__(self, getter):self.getter = getterself._cache = {}def __get__(self, instance, owner):if instance is None:return selfif instance not in self._cache:self._cache[instance] = self.getter(instance)return self._cache[instance]def __set__(self, instance, value):self._cache[instance] = valuedef __delete__(self, instance):if instance in self._cache:del self._cache[instance]class Person:def __init__(self, name, age):self.name = nameself.age = age@CachedPropertydef full_name(self):print("Calculating full name...")return f"{self.name} Smith"@propertydef age(self):return self._age@age.setterdef age(self, value):if value < 0:raise ValueError("Age cannot be negative")self._age = valuep = Person("John", 30)
print(p.full_name) # Output: Calculating full name... John Smith
print(p.full_name) # Output: John Smith (from cache)p.age = 40
print(p.age) # Output: 40p.age = -10 # Raises ValueError: Age cannot be negative
在這個(gè)場(chǎng)景下,self
和 instance
的區(qū)別如下:
-
self
:self
代表的是Person
類本身的實(shí)例,也就是Person
類的一個(gè)對(duì)象。- 在
__get__
方法中,self
指向的是Person
類的age
屬性本身,而不是某個(gè)特定的Person
對(duì)象。
-
instance
:instance
代表的是正在訪問(wèn)age
屬性的Person
對(duì)象實(shí)例。- 在
__get__
方法中,instance
指向的是調(diào)用age
屬性的具體Person
對(duì)象,比如上例中的person
對(duì)象。
簡(jiǎn)單來(lái)說(shuō):
self
指向的是屬性本身(即age
屬性),而instance
指向的是正在訪問(wèn)該屬性的對(duì)象實(shí)例。self
是屬性級(jí)別的,而instance
是對(duì)象級(jí)別的。owner
是屬性的類對(duì)象
這個(gè)區(qū)別很重要,因?yàn)樵?__get__
方法中,我們需要根據(jù)具體的 Person
對(duì)象實(shí)例(instance
)來(lái)計(jì)算年齡,而不是直接使用 self
(即 age
屬性本身)。
方法描述符
class Calculator:def __init__(self):self.num1 = 0self.num2 = 0def __call__(self, a, b):self.num1 = aself.num2 = breturn selfdef add(self):return self.num1 + self.num2calc = Calculator()
result = calc(10, 20)
print(result) # 結(jié)果為30
解釋:
__call__
方法描述符允許將Calculator
類本身作為函數(shù)調(diào)用。- 在
__call__
方法中,self
參數(shù)表示Calculator
對(duì)象,a
和b
參數(shù)表示方法參數(shù)。 - 方法返回
Calculator
對(duì)象本身,以便可以繼續(xù)使用其方法。
優(yōu)點(diǎn):
- 簡(jiǎn)化了方法調(diào)用過(guò)程。
- 允許將類作為函數(shù)使用。
- 提高了代碼可讀性。
注意事項(xiàng):
__call__
方法描述符僅適用于類。- 如果
__call__
方法描述符不正確定義,會(huì)導(dǎo)致錯(cuò)誤。
實(shí)現(xiàn)緩存
在這個(gè)例子中,當(dāng)我們嘗試訪問(wèn)一個(gè)實(shí)例對(duì)象的屬性時(shí),__get__
方法會(huì)被調(diào)用。如果實(shí)例對(duì)象沒(méi)有該屬性的緩存值,它會(huì)調(diào)用 self.func(instance)
來(lái)計(jì)算屬性值,并將其緩存在實(shí)例對(duì)象上。
這種技術(shù)被稱為"惰性計(jì)算"(lazy evaluation),它可以提高性能,因?yàn)閷傩灾抵挥性诘谝淮伪辉L問(wèn)時(shí)才會(huì)計(jì)算。之后,后續(xù)的訪問(wèn)都會(huì)直接返回緩存的值,而不需要再次計(jì)算。
下面是一個(gè)更具體的例子:
class LazyProperty:def __init__(self, func):self.func = funcself.cache_name = f"_{func.__name__}"def __get__(self, instance, owner):if instance is None:return selfif not hasattr(instance, self.cache_name):value = self.func(instance)setattr(instance, self.cache_name, value)return getattr(instance, self.cache_name)class Person:def __init__(self, name, age):self.name = nameself.age = age@LazyPropertydef full_name(self):print("Calculating full name...")return f"{self.name} Smith"person = Person("Alice", 30)
print(person.full_name) # 輸出: "Calculating full name..." 和 "Alice Smith"
print(person.full_name) # 輸出: "Alice Smith"
在這個(gè)例子中,我們定義了一個(gè) LazyProperty
描述符類,它在第一次訪問(wèn) full_name
屬性時(shí)計(jì)算并緩存該值。后續(xù)訪問(wèn)都會(huì)直接返回緩存的值,而不需要再次計(jì)算。
總的來(lái)說(shuō),self.func(instance)
是描述符對(duì)象用來(lái)計(jì)算屬性值的方法調(diào)用。通過(guò)使用描述符,我們可以自定義屬性的訪問(wèn)行為,實(shí)現(xiàn)惰性計(jì)算等優(yōu)化手段,提高代碼的性能和可維護(hù)性。