搜尋

项目地址: https://git.io/pytips

Python 的修饰器是一种语法糖(Syntactic Sugar),也就是说:

@decorator@wrapdef func():    pass

是下面语法的一种简写:

def func():    passfunc = decorator(wrap(func))

关于修饰器的两个主要问题:

  1. 修饰器用来修饰谁

  2. 谁可以作为修饰器

修饰函数

修饰器最常见的用法是修饰新定义的函数,在 0x0d 上下文管理器 中提到上下文管理器主要是为了 更优雅地完成善后工作 ,而修饰器通常用于扩展函数的行为或属性:

def log(func):    def wraper():        print("INFO: Starting {}".format(func.__name__))        func()        print("INFO: Finishing {}".format(func.__name__))    return wraper@logdef run():    print("Running run...")run()
INFO: Starting runRunning run...INFO: Finishing run

修饰类

除了修饰函数之外,Python 3.0 之后增加了对新定义类的修饰( PEP 3129 ),但是对于类别属性的修改可以通过 Metaclasses 或继承来实现,而新增加的类别修饰器更多是出于 Jython 以及 IronPython 的考虑,但其语法还是很一致的:

from time import sleep, timedef timer(Cls):    def wraper():        s = time()        obj = Cls()        e = time()        print("Cost {:.3f}s to init.".format(e - s))        return obj    return wraper@timerclass Obj:    def __init__(self):        print("Hello")        sleep(3)        print("Obj")o = Obj()
HelloObjCost 3.005s to init.

类作为修饰器

上面两个例子都是以函数作为修饰器,因为函数才可以被调用(callable) decorator(wrap(func)) 。除了函数之外,我们也可以定义可被调用的类,只要添加 __call__ 方法即可:

class HTML(object):    """        Baking HTML Tags!    """    def __init__(self, tag="p"):        print("LOG: Baking Tag <{}>!".format(tag))        self.tag = tag    def __call__(self, func):        return lambda: "<{0}>{1}</{0}>".format(self.tag, func(), self.tag)@HTML("html")@HTML("body")@HTML("div")def body():    return "Hello"print(body())
LOG: Baking Tag <html>!LOG: Baking Tag <body>!LOG: Baking Tag <div>!<html><body><div>Hello</div></body></html>

传递参数

在实际使用过程中,我们可能需要向修饰器传递参数,也有可能需要向被修饰的函数(或类)传递参数。按照语法约定,只要修饰器 @decorator 中的 decorator 是可调用即可, decorator(123) 如果返回一个新的可调用函数,那么也是合理的,上面的 @HTML('html') 即是一例,下面再以 flask 的路由修饰器为例说明如何传递参数给修饰器:

RULES = {}def route(rule):    def decorator(hand):        RULES.update({rule: hand})        return hand    return decorator@route("/")def index():    print("Hello world!")def home():    print("Welcome Home!")home = route("/home")(home)index()home()print(RULES)
Hello world!Welcome Home!{'/': <function index at 0x10706f730>, '/home': <function home at 0x10706f8c8>}

向被修饰的函数传递参数,要看我们的修饰器是如何作用的,如果像上面这个例子一样未执行被修饰函数只是将其原模原样地返回,则不需要任何处理(这就把函数当做普通的值一样看待即可):

@route("/login")def login(user = "user", pwd = "pwd"):    print("DB.findOne({{{}, {}}})".format(user, pwd))login("hail", "python")
DB.findOne({hail, python})

如果需要在修饰器内执行,则需要稍微变动一下:

def log(f):    def wraper(*args, **kargs):        print("INFO: Start Logging")        f(*args, **kargs)        print("INFO: Finish Logging")    return wraper@logdef run(hello = "world"):    print("Hello {}".format(hello))run("Python")
INFO: Start LoggingHello PythonINFO: Finish Logging

functools

由于修饰器将函数(或类)进行包装之后重新返回: func = decorator(func) ,那么有可能改变原本函数(或类)的一些信息,以上面的 HTML 修饰器为例:

@HTML("body")def body():    """        return body content    """    return "Hello, body!"print(body.__name__)print(body.__doc__)
LOG: Baking Tag <body>!<lambda>None

因为 body = HTML("body")(body) ,而 HTML("body").__call__() 返回的是一个 lambda 函数,因此 body 已经被替换成了 lambda ,虽然都是可执行的函数,但原来定义的 body 中的一些属性,例如 __doc__ / __name__ / __module__ 都被替换了(在本例中 __module__ 没变因为都在同一个文件中)。为了解决这一问题 Python 提供了 functools 标准库,其中包括了 update_wrapper 和 wraps 两个方法( 源码 )。其中 update_wrapper 就是用来将原来函数的信息赋值给修饰器中返回的函数:

from functools import update_wrapper"""functools.update_wrapper(wrapper, wrapped[, assigned][, updated])"""class HTML(object):    """        Baking HTML Tags!    """    def __init__(self, tag="p"):        print("LOG: Baking Tag <{}>!".format(tag))        self.tag = tag    def __call__(self, func):        wraper = lambda: "<{0}>{1}</{0}>".format(self.tag, func(), self.tag)        update_wrapper(wraper, func)        return wraper@HTML("body")def body():    """        return body content!    """    return "Hello, body!"print(body.__name__)print(body.__doc__)
LOG: Baking Tag <body>!body        return body content!    

有趣的是 update_wrapper 的用法本身就很像是修饰器,因此 functools.wraps 就利用 functools.partial (还记得函数式编程中的偏应用吧!)将其变成一个修饰器:

from functools import update_wrapper, partialdef my_wraps(wrapped):    return partial(update_wrapper, wrapped=wrapped)def log(func):    @my_wraps(func)    def wraper():        print("INFO: Starting {}".format(func.__name__))        func()        print("INFO: Finishing {}".format(func.__name__))    return wraper@logdef run():    """    Docs' of run    """    print("Running run...")print(run.__name__)print(run.__doc__)
run    Docs' of run    

欢迎关注公众号 PyHub!

参考

  1. Python修饰器的函数式编程

陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
HTML中的布爾屬性是什麼?舉一些例子。HTML中的布爾屬性是什麼?舉一些例子。Apr 25, 2025 am 12:01 AM

布爾屬性是HTML中的特殊屬性,不需要值即可激活。 1.布爾屬性通過存在與否控制元素行為,如disabled禁用輸入框。 2.它們的工作原理是瀏覽器解析時根據屬性的存在改變元素行為。 3.基本用法是直接添加屬性,高級用法可通過JavaScript動態控制。 4.常見錯誤是誤以為需要設置值,正確寫法應簡潔。 5.最佳實踐是保持代碼簡潔,合理使用布爾屬性以優化網頁性能和用戶體驗。

如何驗證您的HTML代碼?如何驗證您的HTML代碼?Apr 24, 2025 am 12:04 AM

HTML代碼可以通過在線驗證器、集成工具和自動化流程來確保其清潔度。 1)使用W3CMarkupValidationService在線驗證HTML代碼。 2)在VisualStudioCode中安裝並配置HTMLHint擴展進行實時驗證。 3)利用HTMLTidy在構建流程中自動驗證和清理HTML文件。

HTML與CSS和JavaScript:比較Web技術HTML與CSS和JavaScript:比較Web技術Apr 23, 2025 am 12:05 AM

HTML、CSS和JavaScript是構建現代網頁的核心技術:1.HTML定義網頁結構,2.CSS負責網頁外觀,3.JavaScript提供網頁動態和交互性,它們共同作用,打造出用戶體驗良好的網站。

HTML作為標記語言:其功能和目的HTML作為標記語言:其功能和目的Apr 22, 2025 am 12:02 AM

HTML的功能是定義網頁的結構和內容,其目的在於提供一種標準化的方式來展示信息。 1)HTML通過標籤和屬性組織網頁的各個部分,如標題和段落。 2)它支持內容與表現分離,提升維護效率。 3)HTML具有可擴展性,允許自定義標籤增強SEO。

HTML,CSS和JavaScript的未來:網絡開發趨勢HTML,CSS和JavaScript的未來:網絡開發趨勢Apr 19, 2025 am 12:02 AM

HTML的未來趨勢是語義化和Web組件,CSS的未來趨勢是CSS-in-JS和CSSHoudini,JavaScript的未來趨勢是WebAssembly和Serverless。 1.HTML的語義化提高可訪問性和SEO效果,Web組件提升開發效率但需注意瀏覽器兼容性。 2.CSS-in-JS增強樣式管理靈活性但可能增大文件體積,CSSHoudini允許直接操作CSS渲染。 3.WebAssembly優化瀏覽器應用性能但學習曲線陡,Serverless簡化開發但需優化冷啟動問題。

HTML:結構,CSS:樣式,JavaScript:行為HTML:結構,CSS:樣式,JavaScript:行為Apr 18, 2025 am 12:09 AM

HTML、CSS和JavaScript在Web開發中的作用分別是:1.HTML定義網頁結構,2.CSS控製網頁樣式,3.JavaScript添加動態行為。它們共同構建了現代網站的框架、美觀和交互性。

HTML的未來:網絡設計的發展和趨勢HTML的未來:網絡設計的發展和趨勢Apr 17, 2025 am 12:12 AM

HTML的未來充滿了無限可能。 1)新功能和標準將包括更多的語義化標籤和WebComponents的普及。 2)網頁設計趨勢將繼續向響應式和無障礙設計發展。 3)性能優化將通過響應式圖片加載和延遲加載技術提升用戶體驗。

HTML與CSS vs. JavaScript:比較概述HTML與CSS vs. JavaScript:比較概述Apr 16, 2025 am 12:04 AM

HTML、CSS和JavaScript在網頁開發中的角色分別是:HTML負責內容結構,CSS負責樣式,JavaScript負責動態行為。 1.HTML通過標籤定義網頁結構和內容,確保語義化。 2.CSS通過選擇器和屬性控製網頁樣式,使其美觀易讀。 3.JavaScript通過腳本控製網頁行為,實現動態和交互功能。

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

SAP NetWeaver Server Adapter for Eclipse

SAP NetWeaver Server Adapter for Eclipse

將Eclipse與SAP NetWeaver應用伺服器整合。

DVWA

DVWA

Damn Vulnerable Web App (DVWA) 是一個PHP/MySQL的Web應用程序,非常容易受到攻擊。它的主要目標是成為安全專業人員在合法環境中測試自己的技能和工具的輔助工具,幫助Web開發人員更好地理解保護網路應用程式的過程,並幫助教師/學生在課堂環境中教授/學習Web應用程式安全性。 DVWA的目標是透過簡單直接的介面練習一些最常見的Web漏洞,難度各不相同。請注意,該軟體中

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

VSCode Windows 64位元 下載

VSCode Windows 64位元 下載

微軟推出的免費、功能強大的一款IDE編輯器