資訊內(nèi)容
Python中的裝飾器是什么?裝飾器是如何工作的?
CaT少兒編程網(wǎng)-https://www.pxcodes.compython很早就引入了裝飾器——在PEP-318中,作為一種簡(jiǎn)化函數(shù)和方法定義方式的機(jī)制,這些函數(shù)和方法在初始定義之后必須進(jìn)行修改。CaT少兒編程網(wǎng)-https://www.pxcodes.com
這樣做的**初動(dòng)機(jī)之一是,使用classmethod和staticmethod等函數(shù)來(lái)轉(zhuǎn)換方法的原始定義,但是它們需要額外的一行代碼來(lái)修改函數(shù)的初始定義。CaT少兒編程網(wǎng)-https://www.pxcodes.com
一般來(lái)說(shuō),每次必須對(duì)函數(shù)應(yīng)用轉(zhuǎn)換時(shí),我們必須使用modifier函數(shù)調(diào)用它,然后將它重新分配到函數(shù)初始定義時(shí)的名稱中。CaT少兒編程網(wǎng)-https://www.pxcodes.com
例如,假設(shè)有一個(gè)叫作original的函數(shù),在它上面有一個(gè)改變original行為的函數(shù)(叫作modifier),那么我們必須這樣寫:CaT少兒編程網(wǎng)-https://www.pxcodes.com
def original(...): ... original = modifier(original)(相關(guān)免費(fèi)學(xué)習(xí)推薦:python視頻教程)CaT少兒編程網(wǎng)-https://www.pxcodes.com
請(qǐng)注意我們是如何更改函數(shù)并將其重新分配到相同的名稱中去的。這是令人困惑的,很容易出錯(cuò)(假設(shè)有人忘記重新分配函數(shù),或者重新分配了函數(shù),但不在函數(shù)定義之后的行中,而是在更遠(yuǎn)的地方),而且很麻煩。出于這個(gè)原因,Python語(yǔ)言增加了一些語(yǔ)法支持。CaT少兒編程網(wǎng)-https://www.pxcodes.com
前面的示例可以改寫為如下樣式:CaT少兒編程網(wǎng)-https://www.pxcodes.com
@modifier def original(...): ...這意味著裝飾器只是語(yǔ)法糖,用于調(diào)用裝飾器之后的內(nèi)容作為裝飾器本身的第一個(gè)參數(shù),結(jié)果將是裝飾器返回的內(nèi)容。CaT少兒編程網(wǎng)-https://www.pxcodes.com
為了與Python的術(shù)語(yǔ)一致,在我們的示例中modifier稱為裝飾器,original是裝飾函數(shù),通常也被稱為包裝對(duì)象。CaT少兒編程網(wǎng)-https://www.pxcodes.com
雖然該功能**初被認(rèn)為是用于方法和函數(shù)的,但實(shí)際的語(yǔ)法允許它修飾任何類型的對(duì)象,因此我們將研究應(yīng)用于函數(shù)、方法、生成器和類的裝飾器。CaT少兒編程網(wǎng)-https://www.pxcodes.com
**后一點(diǎn)需要注意的是,雖然裝飾器的名稱是正確的(畢竟,裝飾器實(shí)際上是在對(duì)包裝函數(shù)進(jìn)行更改、擴(kuò)展或處理),但不要將它與裝飾器設(shè)計(jì)模式混淆。CaT少兒編程網(wǎng)-https://www.pxcodes.com
5.1.1 裝飾器函數(shù)CaT少兒編程網(wǎng)-https://www.pxcodes.com
函數(shù)可能是對(duì)可以裝飾的Python對(duì)象的**簡(jiǎn)單的表示形式。我們可以在函數(shù)上使用裝飾器來(lái)應(yīng)用各種邏輯——我們可以驗(yàn)證參數(shù)、檢查前置條件、完全改變行為、修改其簽名、緩存結(jié)果(創(chuàng)建原始函數(shù)的內(nèi)存版本)等。CaT少兒編程網(wǎng)-https://www.pxcodes.com
例如,我們將創(chuàng)建一個(gè)實(shí)現(xiàn)retry機(jī)制的基本裝飾器,控制一個(gè)特定的域級(jí)異常并重試一定的次數(shù):CaT少兒編程網(wǎng)-https://www.pxcodes.com
# decorator_function_1.py class ControlledException(Exception): """A generic exception on the program's domain.""" def retry(operation): @wraps(operation) def wrapped(*args, **kwargs): last_raised = None RETRIES_LIMIT = 3 for _ in range(RETRIES_LIMIT): try: return operation(*args, **kwargs) except ControlledException as e: logger.info("retrying %s", operation.__qualname__) last_raised = e raise last_raised return wrapped現(xiàn)在可以忽略@wrap的使用,因?yàn)樗鼘⒃诹硪还?jié)中討論。在for循環(huán)中使用“_”,意味著這個(gè)數(shù)字被分配給一個(gè)我們目前不感興趣的變量,因?yàn)樗辉趂or循環(huán)中使用(在Python中,將被忽略的值命名為“_”是一個(gè)常見(jiàn)的習(xí)慣用法)。CaT少兒編程網(wǎng)-https://www.pxcodes.com
retry裝飾器不接收任何參數(shù),所以它可以很容易地應(yīng)用于任何函數(shù),如下所示:CaT少兒編程網(wǎng)-https://www.pxcodes.com
@retry def run_operation(task): """Run a particular task, simulating some failures on its execution.""" return task.run()正如一開(kāi)始所解釋的,在run_operation之上@retry的定義只是Python提供的語(yǔ)法糖,用于實(shí)際執(zhí)行run_operation = retry(run_operation)。CaT少兒編程網(wǎng)-https://www.pxcodes.com
在這個(gè)有限的示例中,我們可以看到如何用裝飾器創(chuàng)建一個(gè)通用的retry操作,在某些確定的條件下(在本示例中,表示為可能與超時(shí)相關(guān)的異常),該操作將允許多次調(diào)用裝飾后的代碼。CaT少兒編程網(wǎng)-https://www.pxcodes.com
5.1.2 裝飾類CaT少兒編程網(wǎng)-https://www.pxcodes.com
類也可以被裝飾(PEP-3129),其裝飾方法與語(yǔ)法函數(shù)的裝飾方法相同。**的區(qū)別是,在為裝飾器編寫代碼時(shí),我們必須考慮到所接收的是一個(gè)類,而不是一個(gè)函數(shù)。CaT少兒編程網(wǎng)-https://www.pxcodes.com
一些實(shí)踐者可能會(huì)認(rèn)為裝飾類是相當(dāng)復(fù)雜的事情,這樣的場(chǎng)景可能會(huì)損害可讀性,因?yàn)槲覀儗⒃陬愔新暶饕恍傩院头椒?,但是在幕后,裝飾器可能會(huì)應(yīng)用一些變化,從而呈現(xiàn)一個(gè)完全不同的類。CaT少兒編程網(wǎng)-https://www.pxcodes.com
這種評(píng)定是正確的,但只有在裝飾類技術(shù)被嚴(yán)重濫用的情況下成立??陀^上,這與裝飾功能沒(méi)有什么不同;畢竟,類和函數(shù)一樣,都只是Python生態(tài)系統(tǒng)中的一種類型的對(duì)象而已。在5.4節(jié)中,我們將再次審視這個(gè)問(wèn)題的優(yōu)缺點(diǎn),但是這里只探索裝飾器的優(yōu)點(diǎn),尤其是適用于類的裝飾器的優(yōu)點(diǎn)。 CaT少兒編程網(wǎng)-https://www.pxcodes.com
(1)重用代碼和DRY原則的所有好處。類裝飾器的一個(gè)有效情況是,強(qiáng)制多個(gè)類符合特定的接口或標(biāo)準(zhǔn)(通過(guò)只在將應(yīng)用于多個(gè)類的裝飾器中進(jìn)行一次檢查)。CaT少兒編程網(wǎng)-https://www.pxcodes.com
(2)可以創(chuàng)建更小或更簡(jiǎn)單的類——這些類稍后將由裝飾器進(jìn)行增強(qiáng)。CaT少兒編程網(wǎng)-https://www.pxcodes.com
(3)如果使用裝飾器,那么需要應(yīng)用到特定類上的轉(zhuǎn)換邏輯將更容易維護(hù),而不會(huì)使用更復(fù)雜的(通常是不鼓勵(lì)使用的)方法,如元類。CaT少兒編程網(wǎng)-https://www.pxcodes.com
在裝飾器的所有可能應(yīng)用程序中,我們將探索一個(gè)簡(jiǎn)單的示例,以了解裝飾器可以用于哪些方面。記住,這不是類裝飾器的**應(yīng)用程序類型,而且給出的代碼還可以有許多其他解決方案。所有這些解決方案都有優(yōu)缺點(diǎn),之所以選擇裝飾器,是為了說(shuō)明它們的用處。CaT少兒編程網(wǎng)-https://www.pxcodes.com
回顧用于監(jiān)視平臺(tái)的事件系統(tǒng),現(xiàn)在需要轉(zhuǎn)換每個(gè)事件的數(shù)據(jù)并將其發(fā)送到外部系統(tǒng)。然而,在選擇如何發(fā)送數(shù)據(jù)時(shí),每種類型的事件可能都有自己的特殊性。CaT少兒編程網(wǎng)-https://www.pxcodes.com
特別是,登錄事件可能包含敏感信息,例如我們希望隱藏的憑據(jù)。時(shí)間戳等其他領(lǐng)域的字段可能也需要一些轉(zhuǎn)換,因?yàn)槲覀兿M蕴囟ǖ母袷斤@示它們。符合這些要求的第一次嘗試很簡(jiǎn)單,就像有一個(gè)映射到每個(gè)特定事件的類,并知道如何序列化它那樣:CaT少兒編程網(wǎng)-https://www.pxcodes.com
class LoginEventSerializer: def __init__(self, event): self.event = event def serialize(self) -> dict: return { "username": self.event.username, "password": "**redacted**", "ip": self.event.ip, "timestamp": self.event.timestamp.strftime("%Y-%m-%d %H:%M"), } class LoginEvent: SERIALIZER = LoginEventSerializer def __init__(self, username, password, ip, timestamp): self.username = username self.password = password self.ip = ip self.timestamp = timestamp def serialize(self) -> dict: return self.SERIALIZER(self).serialize()在這里,我們聲明一個(gè)類。該類將直接映射到登錄事件,其中包含它的一些邏輯——隱藏密碼字段,并根據(jù)需要格式化時(shí)間戳。CaT少兒編程網(wǎng)-https://www.pxcodes.com
雖然這是可行的,可能開(kāi)始看起來(lái)是一個(gè)不錯(cuò)的選擇,但隨著時(shí)間的推移,若要擴(kuò)展系統(tǒng),就會(huì)發(fā)現(xiàn)一些問(wèn)題。CaT少兒編程網(wǎng)-https://www.pxcodes.com
(1)類太多。隨著事件數(shù)量的增多,序列化類的數(shù)量將以相同的量級(jí)增長(zhǎng),因?yàn)樗鼈兪且灰挥成涞?。CaT少兒編程網(wǎng)-https://www.pxcodes.com
(2)解決方案不夠靈活。如果我們需要重用部分組件(例如,需要把密碼藏在也有類似需求的另一個(gè)類型的事件中),就不得不將其提取到一個(gè)函數(shù),但也要從多個(gè)類中調(diào)用它,這意味著我們沒(méi)有重用那么多代碼。CaT少兒編程網(wǎng)-https://www.pxcodes.com
(3)樣板文件。serialize()方法必須出現(xiàn)在所有事件類中,同時(shí)調(diào)用相同的代碼。盡管我們可以將其提取到另一個(gè)類中(創(chuàng)建mixin),但這似乎沒(méi)有很好地使用繼承。CaT少兒編程網(wǎng)-https://www.pxcodes.com
另一種解決方案是能夠動(dòng)態(tài)構(gòu)造一個(gè)對(duì)象:給定一組過(guò)濾器(轉(zhuǎn)換函數(shù))和一個(gè)事件實(shí)例,該對(duì)象能夠通過(guò)將過(guò)濾器應(yīng)用于其字段的方式序列化它。然后,我們只需要定義轉(zhuǎn)換每種字段類型的函數(shù),并通過(guò)組合這些函數(shù)創(chuàng)建序列化器。CaT少兒編程網(wǎng)-https://www.pxcodes.com
一旦有了這個(gè)對(duì)象,我們就可以裝飾類以添加serialize()方法。該方法只會(huì)調(diào)用這些序列化對(duì)象本身:CaT少兒編程網(wǎng)-https://www.pxcodes.com
def hide_field(field) -> str: return "**redacted**" def format_time(field_timestamp: datetime) -> str: return field_timestamp.strftime("%Y-%m-%d %H:%M") def show_original(event_field): return event_field class EventSerializer: def __init__(self, serialization_fields: dict) -> None: self.serialization_fields = serialization_fields def serialize(self, event) -> dict: return { field: transformation(getattr(event, field)) for field, transformation in self.serialization_fields.items() } class Serialization: def __init__(self, **transformations): self.serializer = EventSerializer(transformations) def __call__(self, event_class): def serialize_method(event_instance): return self.serializer.serialize(event_instance) event_class.serialize = serialize_method return event_class @Serialization( username=show_original, password=hide_field, ip=show_original, timestamp=format_time, ) class LoginEvent: def __init__(self, username, password, ip, timestamp): self.username = username self.password = password self.ip = ip self.timestamp = timestamp注意,裝飾器讓你更容易知道如何處理每個(gè)字段,而不必查看另一個(gè)類的代碼。僅通過(guò)讀取傳遞給類裝飾器的參數(shù),我們就知道用戶名和IP地址將保持不變,密碼將被隱藏,時(shí)間戳將被格式化。CaT少兒編程網(wǎng)-https://www.pxcodes.com
現(xiàn)在,類的代碼不需要定義serialize()方法,也不需要從實(shí)現(xiàn)它的mixin類進(jìn)行擴(kuò)展,因?yàn)檫@些都將由裝飾器添加。實(shí)際上,這可能是創(chuàng)建類裝飾器的**理由,因?yàn)槿绻皇沁@樣的話,序列化對(duì)象可能是LoginEvent的一個(gè)類屬性,但是它通過(guò)向該類添加一個(gè)新方法來(lái)更改類,這使得創(chuàng)建該類裝飾器變得不可能。CaT少兒編程網(wǎng)-https://www.pxcodes.com
我們還可以使用另一個(gè)類裝飾器,通過(guò)定義類的屬性來(lái)實(shí)現(xiàn)init方法的邏輯,但這超出了本例的范圍。CaT少兒編程網(wǎng)-https://www.pxcodes.com
通過(guò)使用Python 3.7+ 中的這個(gè)類裝飾器(PEP-557),可以按更簡(jiǎn)潔的方式重寫前面的示例,而不使用init的樣板代碼,如下所示:CaT少兒編程網(wǎng)-https://www.pxcodes.com
from dataclasses import dataclass from datetime import datetime @Serialization( username=show_original, password=hide_field, ip=show_original, timestamp=format_time, ) @dataclass class LoginEvent: username: str password: str ip: str timestamp: datetime5.1.3 其他類型的裝飾器CaT少兒編程網(wǎng)-https://www.pxcodes.com
既然我們已經(jīng)知道了裝飾器的@語(yǔ)法的實(shí)際含義,就可以得出這樣的結(jié)論:可以裝飾的不僅是函數(shù)、方法或類;實(shí)際上,任何可以定義的東西(如生成器、協(xié)同程序甚至是裝飾過(guò)的對(duì)象)都可以裝飾,這意味著裝飾器可以堆疊起來(lái)。CaT少兒編程網(wǎng)-https://www.pxcodes.com
前面的示例展示了如何鏈接裝飾器。我們先定義類,然后將@dataclass應(yīng)用于該類——它將該類轉(zhuǎn)換為數(shù)據(jù)類,充當(dāng)這些屬性的容器。之后,通過(guò)@Serialization把邏輯應(yīng)用到該類上,從而生成一個(gè)新類,其中添加了新的serialize()方法。CaT少兒編程網(wǎng)-https://www.pxcodes.com
裝飾器另一個(gè)好的用法是用于應(yīng)該用作協(xié)同程序的生成器。我們將在第7章中探討生成器和協(xié)同程序的細(xì)節(jié),其主要思想是,在向新創(chuàng)建的生成器發(fā)送任何數(shù)據(jù)之前,必須通過(guò)調(diào)用next()將后者推進(jìn)到下一個(gè)yield語(yǔ)句。這是每個(gè)用戶都必須記住的手動(dòng)過(guò)程,因此很容易出錯(cuò)。我們可以輕松創(chuàng)建一個(gè)裝飾器,使其接收生成器作為參數(shù),調(diào)用next(),然后返回生成器。CaT少兒編程網(wǎng)-https://www.pxcodes.com
5.1.4 將參數(shù)傳遞給裝飾器CaT少兒編程網(wǎng)-https://www.pxcodes.com
至此,我們已經(jīng)將裝飾器看作Python中的一個(gè)強(qiáng)大工具。如果我們可以將參數(shù)傳遞給裝飾器,使其邏輯更加抽象,那么其功能可能會(huì)更加強(qiáng)大。CaT少兒編程網(wǎng)-https://www.pxcodes.com
有幾種實(shí)現(xiàn)裝飾器的方法可以接收參數(shù),但是接下來(lái)我們只討論**常見(jiàn)的方法。第一種方法是將裝飾器創(chuàng)建為帶有新的間接層的嵌套函數(shù),使裝飾器中的所有內(nèi)容深入一層。第二種方法是為裝飾器使用一個(gè)類。CaT少兒編程網(wǎng)-https://www.pxcodes.com
通常,第二種方法更傾向于可讀性,因?yàn)閺膶?duì)象的角度考慮,其要比3個(gè)或3個(gè)以上使用閉包的嵌套函數(shù)更容易。但是,為了完整起見(jiàn),我們將對(duì)這兩種方法進(jìn)行探討,以便你可以選擇使用**適合當(dāng)前問(wèn)題的方法。CaT少兒編程網(wǎng)-https://www.pxcodes.com
1.帶有嵌套函數(shù)的裝飾器CaT少兒編程網(wǎng)-https://www.pxcodes.com
粗略地說(shuō),裝飾器的基本思想是創(chuàng)建一個(gè)返回函數(shù)的函數(shù)(通常稱為高階函數(shù))。在裝飾器主體中定義的內(nèi)部函數(shù)將是實(shí)際被調(diào)用的函數(shù)。CaT少兒編程網(wǎng)-https://www.pxcodes.com
現(xiàn)在,如果希望將參數(shù)傳遞給它,就需要另一間接層。第一個(gè)函數(shù)將接收參數(shù),在該函數(shù)中,我們將定義一個(gè)新函數(shù)(它將是裝飾器),而這個(gè)新函數(shù)又將定義另一個(gè)新函數(shù),即裝飾過(guò)程返回的函數(shù)。這意味著我們將至少有3層嵌套函數(shù)。CaT少兒編程網(wǎng)-https://www.pxcodes.com
如果你到目前為止還不明白上述內(nèi)容的含義,也不用擔(dān)心,待查看下面給出的示例之后,就會(huì)明白了。CaT少兒編程網(wǎng)-https://www.pxcodes.com
第一個(gè)示例是,裝飾器在一些函數(shù)上實(shí)現(xiàn)重試功能。這是個(gè)好主意,只是有個(gè)問(wèn)題:實(shí)現(xiàn)不允許指定重試次數(shù),只允許在裝飾器中指定一個(gè)固定的次數(shù)。CaT少兒編程網(wǎng)-https://www.pxcodes.com
現(xiàn)在,我們希望能夠指出每個(gè)示例有多少次重試,也許甚至可以為這個(gè)參數(shù)添加一個(gè)默認(rèn)值。為了實(shí)現(xiàn)這個(gè)功能,我們需要用到另一層嵌套函數(shù)——先用于參數(shù),然后用于裝飾器本身。CaT少兒編程網(wǎng)-https://www.pxcodes.com
這是因?yàn)槿缦麓a:CaT少兒編程網(wǎng)-https://www.pxcodes.com
@retry(arg1, arg2,... )必須返回裝飾器,因?yàn)锧語(yǔ)法將把計(jì)算結(jié)果應(yīng)用到要裝飾的對(duì)象上。從語(yǔ)義上講,它可以翻譯成如下內(nèi)容:CaT少兒編程網(wǎng)-https://www.pxcodes.com
<original_function> = retry(arg1, arg2, ....)(<original_function>)除了所需的重試次數(shù),我們還可以指明希望控制的異常類型。支持新需求的新版本代碼可能是這樣的:CaT少兒編程網(wǎng)-https://www.pxcodes.com
RETRIES_LIMIT = 3 def with_retry(retries_limit=RETRIES_LIMIT, allowed_exceptions=None): allowed_exceptions = allowed_exceptions or (ControlledException,) def retry(operation): @wraps(operation) def wrapped(*args, **kwargs): last_raised = None for _ in range(retries_limit): try: return operation(*args, **kwargs) except allowed_exceptions as e: logger.info("retrying %s due to %s", operation, e) last_raised = e raise last_raised return wrapped return retry下面是這個(gè)裝飾器如何應(yīng)用于函數(shù)的一些示例,其中顯示了它接收的不同選項(xiàng):CaT少兒編程網(wǎng)-https://www.pxcodes.com
# decorator_parametrized_1.py @with_retry() def run_operation(task): return task.run() @with_retry(retries_limit=5) def run_with_custom_retries_limit(task): return task.run() @with_retry(allowed_exceptions=(AttributeError,)) def run_with_custom_exceptions(task): return task.run() @with_retry( retries_limit=4, allowed_exceptions=(ZeropisionError, AttributeError) ) def run_with_custom_parameters(task): return task.run()2.裝飾器對(duì)象CaT少兒編程網(wǎng)-https://www.pxcodes.com
前面的示例需要用到3層嵌套函數(shù)。首先,這將是一個(gè)用于接收我們想要使用的裝飾器的參數(shù)。在這個(gè)函數(shù)中,其余的函數(shù)是使用這些參數(shù)和裝飾器邏輯的閉包。CaT少兒編程網(wǎng)-https://www.pxcodes.com
更簡(jiǎn)潔的實(shí)現(xiàn)方法是用一個(gè)類定義裝飾器。在這種情況下,我們可以在__init__方法中傳遞參數(shù),然后在名為_(kāi)_call__的魔法方法上實(shí)現(xiàn)裝飾器的邏輯。CaT少兒編程網(wǎng)-https://www.pxcodes.com
裝飾器的代碼如下所示:CaT少兒編程網(wǎng)-https://www.pxcodes.com
class WithRetry: def __init__(self, retries_limit=RETRIES_LIMIT, allowed_exceptions=None): self.retries_limit = retries_limit self.allowed_exceptions = allowed_exceptions or (ControlledException,) def __call__(self, operation): @wraps(operation) def wrapped(*args, **kwargs): last_raised = None for _ in range(self.retries_limit): try: return operation(*args, **kwargs) except self.allowed_exceptions as e: logger.info("retrying %s due to %s", operation, e) last_raised = e raise last_raised return wrapped這個(gè)裝飾器可以像之前的一樣應(yīng)用,就像這樣:CaT少兒編程網(wǎng)-https://www.pxcodes.com
@WithRetry(retries_limit=5) def run_with_custom_retries_limit(task): return task.run()注意Python語(yǔ)法在這里是如何起作用的,這一點(diǎn)很重要。首先,我們創(chuàng)建對(duì)象,這樣在應(yīng)用@操作之前,對(duì)象已經(jīng)創(chuàng)建好了,并且其參數(shù)傳遞給它了,用這些參數(shù)初始化這個(gè)對(duì)象,如init方法中定義的那樣。在此之后,我們將調(diào)用@操作,這樣該對(duì)象將包裝名為run_with_custom_reries_limit的函數(shù),而這意味著它將被傳遞給call這個(gè)魔法方法。CaT少兒編程網(wǎng)-https://www.pxcodes.com
在call這個(gè)魔法方法中,我們定義了裝飾器的邏輯,就像通常所做的那樣——包裝了原始函數(shù),返回一個(gè)新的函數(shù),其中包含所要的邏輯。CaT少兒編程網(wǎng)-https://www.pxcodes.com
5.1.5 充分利用裝飾器CaT少兒編程網(wǎng)-https://www.pxcodes.com
本節(jié)介紹一些充分利用裝飾器的常見(jiàn)模式。在有些常見(jiàn)的場(chǎng)景中使用裝飾器是個(gè)非常好的選擇。CaT少兒編程網(wǎng)-https://www.pxcodes.com
可用于應(yīng)用程序的裝飾器數(shù)不勝數(shù),下面僅列舉幾個(gè)**常見(jiàn)或相關(guān)的。CaT少兒編程網(wǎng)-https://www.pxcodes.com
(1)轉(zhuǎn)換參數(shù)。更改函數(shù)的簽名以公開(kāi)更好的API,同時(shí)封裝關(guān)于如何處理和轉(zhuǎn)換參數(shù)的詳細(xì)信息。CaT少兒編程網(wǎng)-https://www.pxcodes.com
(2)跟蹤代碼。記錄函數(shù)及其參數(shù)的執(zhí)行情況。CaT少兒編程網(wǎng)-https://www.pxcodes.com
(3)驗(yàn)證參數(shù)。CaT少兒編程網(wǎng)-https://www.pxcodes.com
(4)實(shí)現(xiàn)重試操作。CaT少兒編程網(wǎng)-https://www.pxcodes.com
(5)通過(guò)把一些(重復(fù)的)邏輯移到裝飾器中來(lái)簡(jiǎn)化類。CaT少兒編程網(wǎng)-https://www.pxcodes.com
接下來(lái)詳細(xì)討論前兩個(gè)應(yīng)用程序。CaT少兒編程網(wǎng)-https://www.pxcodes.com
1.轉(zhuǎn)換參數(shù)CaT少兒編程網(wǎng)-https://www.pxcodes.com
前文提到,裝飾器可以用來(lái)驗(yàn)證參數(shù)(甚至在DbC的概念下強(qiáng)制一些前置條件或后置條件),因此你可能已經(jīng)了解到,這是一些處理或者操控參數(shù)時(shí)使用裝飾器的常用方法。CaT少兒編程網(wǎng)-https://www.pxcodes.com
特別是,在某些情況下,我們會(huì)發(fā)現(xiàn)自己反復(fù)創(chuàng)建類似的對(duì)象,或者應(yīng)用類似的轉(zhuǎn)換,而我們希望將這些轉(zhuǎn)換抽象掉。大多數(shù)時(shí)候,我們可以通過(guò)簡(jiǎn)單地用裝飾器實(shí)現(xiàn)這一點(diǎn)。CaT少兒編程網(wǎng)-https://www.pxcodes.com
2.跟蹤代碼CaT少兒編程網(wǎng)-https://www.pxcodes.com
在本節(jié)中討論跟蹤時(shí),我們將提到一些更通用的內(nèi)容,這些內(nèi)容與處理所要監(jiān)控的函數(shù)的執(zhí)行有關(guān),具體是指:CaT少兒編程網(wǎng)-https://www.pxcodes.com
(1)實(shí)際跟蹤函數(shù)的執(zhí)行(例如,通過(guò)記錄函數(shù)執(zhí)行的行);CaT少兒編程網(wǎng)-https://www.pxcodes.com
(2)監(jiān)控函數(shù)的一些指標(biāo)(如CPU使用量或內(nèi)存占用);CaT少兒編程網(wǎng)-https://www.pxcodes.com
(3)測(cè)量函數(shù)的運(yùn)行時(shí)間;CaT少兒編程網(wǎng)-https://www.pxcodes.com
(4)函數(shù)被調(diào)用時(shí)的日志,以及傳遞給它的參數(shù)。CaT少兒編程網(wǎng)-https://www.pxcodes.com
我們將在5.2節(jié)剖析一個(gè)簡(jiǎn)單的裝飾器示例,該示例記錄了函數(shù)的執(zhí)行情況,包括函數(shù)名和運(yùn)行時(shí)間。CaT少兒編程網(wǎng)-https://www.pxcodes.com
本文摘自《編寫整潔的Python代碼》 CaT少兒編程網(wǎng)-https://www.pxcodes.com
本書介紹Python軟件工程的主要實(shí)踐和原則,旨在幫助讀者編寫更易于維護(hù)和更整潔的代碼。全書共10章:第1章介紹Python語(yǔ)言的基礎(chǔ)知識(shí)和搭建Python開(kāi)發(fā)環(huán)境所需的主要工具;第2章描述Python風(fēng)格代碼,介紹Python中的第一個(gè)習(xí)慣用法;第3章總結(jié)好代碼的一般特征,回顧軟件工程中的一般原則;第4章介紹一套面向?qū)ο筌浖O(shè)計(jì)的原則,即SOLID原則;第5章介紹裝飾器,它是Python的**特性之一;第6章探討描述符,介紹如何通過(guò)描述符從對(duì)象中獲取更多的信息;第7章和第8章介紹生成器以及單元測(cè)試和重構(gòu)的相關(guān)內(nèi)容;第9章回顧Python中**常見(jiàn)的設(shè)計(jì)模式;第10章再次強(qiáng)調(diào)代碼整潔是實(shí)現(xiàn)良好架構(gòu)的基礎(chǔ)。 CaT少兒編程網(wǎng)-https://www.pxcodes.com
本書適合所有python編程愛(ài)好者、對(duì)程序設(shè)計(jì)感興趣的人,以及其他想學(xué)習(xí)更多Python知識(shí)的軟件工程的從業(yè)人員。CaT少兒編程網(wǎng)-https://www.pxcodes.com
相關(guān)免費(fèi)學(xué)習(xí)推薦:python教程(視頻)CaT少兒編程網(wǎng)-https://www.pxcodes.com
以上就是Python中的裝飾器是什么?裝飾器是如何工作的?的詳細(xì)內(nèi)容,更多請(qǐng)關(guān)注少兒編程網(wǎng)其它相關(guān)文章!CaT少兒編程網(wǎng)-https://www.pxcodes.com
- 上一篇
python中階乘怎么表示
簡(jiǎn)介python中階乘的表示方法:首先用def代碼創(chuàng)建函數(shù),并創(chuàng)建一個(gè)變量res;然后寫入forrange循環(huán),并在for循環(huán)當(dāng)中進(jìn)行計(jì)算并且返回res;最后用print代碼打印輸出3的階乘。本教程操作環(huán)境:windows7系統(tǒng)、python3.9版,DELLG3電腦。python中階乘的表示方法:1、
- 下一篇
python中range函數(shù)用法是什么
簡(jiǎn)介python中range函數(shù)用法:【range()】函數(shù)可創(chuàng)建一個(gè)整數(shù)列表,一般用在for循環(huán)中,函數(shù)語(yǔ)法為【range(start,stop[,step])】,其中start是開(kāi)始計(jì)數(shù),stop是停止,step是步長(zhǎng)。本教程操作環(huán)境:windows7系統(tǒng)、python3.9版,DELLG3電腦。p
