亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

保留裝飾功能的簽名

保留裝飾功能的簽名

收到一只叮咚 2019-08-17 15:42:52
保留裝飾功能的簽名假設我編寫了一個裝飾器來做一些非常通用的東西。例如,它可能會將所有參數轉換為特定類型,執行日志記錄,實現memoization等。這是一個例子:def args_as_ints(f):     def g(*args, **kwargs):         args = [int(x) for x in args]         kwargs = dict((k, int(v)) for k, v in kwargs.items())         return f(*args, **kwargs)     return g@args_as_intsdef funny_function(x, y, z=3):     """Computes x*y + 2*z"""     return x*y + 2*z>>> funny_function("3", 4.0, z="5")22到目前為止一切都很好。然而,有一個問題。裝飾函數不保留原始函數的文檔:>>> help(funny_function)Help on function g in module __main__:g(*args, **kwargs)幸運的是,有一個解決方法:def args_as_ints(f):     def g(*args, **kwargs):         args = [int(x) for x in args]         kwargs = dict((k, int(v)) for k, v in kwargs.items())         return f(*args, **kwargs)     g.__name__ = f.__name__     g.__doc__ = f.__doc__    return g@args_as_intsdef funny_function(x, y, z=3):     """Computes x*y + 2*z"""     return x*y + 2*z這次,函數名稱和文檔是正確的:>>> help(funny_function)Help on function funny_function in module __main__:funny_function(*args, **kwargs)     Computes x*y + 2*z但仍存在一個問題:功能簽名是錯誤的。信息“* args,** kwargs”幾乎沒用。該怎么辦?我可以想到兩個簡單但有缺陷的解決方法:1 - 在docstring中包含正確的簽名:def funny_function(x, y, z=3):     """funny_function(x, y, z=3) -- computes x*y + 2*z"""     return x*y + 2*z這很糟糕,因為重復。簽名仍無法在自動生成的文檔中正確顯示。更新函數很容易,忘記更改文檔字符串或打字錯誤。[ 是的,我知道docstring已經復制了函數體這一事實。請忽略這一點; funny_function只是一個隨機的例子。]2 - 不使用裝飾器,或為每個特定簽名使用專用裝飾器:def funny_functions_decorator(f):     def g(x, y, z=3):         return f(int(x), int(y), z=int(z))     g.__name__ = f.__name__     g.__doc__ = f.__doc__    return g這適用于具有相同簽名的一組函數,但一般來說它沒用。正如我在開始時所說,我希望能夠完全使用裝飾器。我正在尋找一種完全通用且自動化的解決方案。所以問題是:有沒有辦法在創建裝飾函數簽名后對其進行編輯?否則,我可以編寫一個提取器來提取函數簽名并在構造裝飾函數時使用該信息而不是“* kwargs,** kwargs”嗎?如何提取該信息?我應該如何構建裝飾函數 - 使用exec?還有其他方法嗎?
查看完整描述

3 回答

?
陪伴而非守候

TA貢獻1757條經驗 獲得超8個贊

這是通過Python的標準庫functools和特定functools.wraps功能來解決的,該功能旨在“?將包裝函數更新為包裝函數?”。但是,它的行為取決于Python版本,如下所示。應用于問題的示例,代碼如下所示:

from?functools?import?wrapsdef?args_as_ints(f):
????@wraps(f)?
????def?g(*args,?**kwargs):
????????args?=?[int(x)?for?x?in?args]
????????kwargs?=?dict((k,?int(v))?for?k,?v?in?kwargs.items())
????????return?f(*args,?**kwargs)
????return?g@args_as_intsdef?funny_function(x,?y,?z=3):
????"""Computes?x*y?+?2*z"""
????return?x*y?+?2*z

在Python 3中執行時,會產生以下結果:

>>>?funny_function("3",?4.0,?z="5")22>>>?help(funny_function)Help?on?function?funny_function?in?module?__main__:funny_function(x,?y,?z=3)
????Computes?x*y?+?2*z

它唯一的缺點是在Python 2中,它不會更新函數的參數列表。在Python 2中執行時,它將產生:

>>>?help(funny_function)Help?on?function?funny_function?in?module?__main__:funny_function(*args,?**kwargs)
????Computes?x*y?+?2*z


查看完整回答
反對 回復 2019-08-17
?
慕森王

TA貢獻1777條經驗 獲得超3個贊

有一個裝飾器模塊,decorator你可以使用裝飾器:

@decoratordef?args_as_ints(f,?*args,?**kwargs):
????args?=?[int(x)?for?x?in?args]
????kwargs?=?dict((k,?int(v))?for?k,?v?in?kwargs.items())
????return?f(*args,?**kwargs)

然后保留方法的簽名和幫助:

>>>?help(funny_function)Help?on?function?funny_function?in?module?__main__:funny_function(x,?y,?z=3)
????Computes?x*y?+?2*z


查看完整回答
反對 回復 2019-08-17
  • 3 回答
  • 0 關注
  • 450 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號