[英]creating decorator out of another decorator (python)
在python上的裝飾器主題上花了幾個小時之后,我仍然遇到兩個問題。
第一; 如果裝飾器沒有參數,則sytntax如下所示:
@decorator
def bye():
return "bye"
這只是一種語法糖,與此相同
bye = decorator(bye)
但是如果我有一個帶參數的裝飾器:
@decorator(*args)
def bye():
return "bye"
“無糖”版本看起來如何? 函數是否作為參數之一傳遞到內部?
bye = decorator("argument", bye)
第二個問題(與第一個更實際的示例有關);
def permission_required(permission):
def wrap(function):
@functools.wraps(function)
def wrapped_func(*args, **kwargs):
if not current_user.can(permission):
abort(403)
return function(*args, **kwargs)
return wrapped_function
return wrap
def admin_required(f):
return permission_required(Permission.ADMINISTER)(f)
在這里, Permission_required裝飾器傳遞給名為admin_required的新創建的裝飾器的返回語句。 我不知道這是如何工作的。 主要是我們返回原始裝飾器+函數的return語句(使用奇怪的語法)。 有人可以詳細說明嗎? -非常歡迎細節
帶有參數的裝飾器被簡單地調用(帶有該參數),以產生另一個裝飾器。 然后,像往常一樣,使用修飾的函數作為其參數來調用該修飾器。 因此翻譯為:
@decorator(*args)
def bye():
return "bye"
將會:
bye = decorator(*args)(bye)
或者,也許您會發現更清晰的如下:
temp = decorator(*args)
bye = temp(bye)
(當然,實際上沒有創建temp
變量。)
在第二個問題中,將@admin_required
定義為@permission_required(Permission.ADMINISTER)
的快捷方式。
當參數以修飾符形式給出時,
@decorator(a, b, c)
def function(): pass
它是寫作的語法糖
def function(): pass
function = decorator(a, b, c)(function)
也就是說, decorator
使用參數a,b,c調用,然后它返回的對象使用唯一的參數function
。
當裝飾器是一個類時,最容易理解這是什么意思。 我將使用您的permission_required
裝飾器作為運行示例。 可以這樣寫:
class permission_required:
def __init__(self, permission):
self.permission = permission
def __call__(self, function):
@functools.wraps(function)
def wrapped_func(*args, **kwargs):
if not current_user.can(permission):
abort(403)
return function(*args, **kwargs)
return wrapped_func
admin_required = permission_required(Permission.ADMINISTER)
當您使用裝飾器時,例如
@permission_required(Permission.DESTRUCTIVE)
def erase_the_database():
raise NotImplemented # TBD: should we even have this?
您首先實例化該類,將Permission.DESTRUCTIVE
傳遞給__init__
,然后將該實例作為一個函數調用,並以erase_the_database
作為參數,該實例將調用__call__
方法,該方法構造包裝的函數並返回它。
以這種方式思考, admin_required
應該更容易理解:它是permission_required
類的一個實例,尚未被調用。 基本上是速記:
@admin_required
def add_user(...): ...
而不是輸入
@permission_required(Permission.ADMINISTER)
def add_user(...): ...
現在,您擁有它的方式...
def permission_required(permission):
def wrap(function):
@functools.wraps(function)
def wrapped_func(*args, **kwargs):
if not current_user.can(permission):
abort(403)
return function(*args, **kwargs)
return wrapped_func
return wrap
確實是寫同一件事的另一種方式。 從permission_required
返回wrap
會隱式創建一個閉包對象 。 可以像函數一樣調用它,並且在執行時調用wrap
。 它記住傳遞給permission_required
的permission
值,以便wrap
可以使用它。 這正是我上面顯示的課程所做的。 (實際上,像C ++和Rust這樣的編譯語言通常通過將閉包改為類定義來實現閉包,如我所展示的那樣。)
請注意, wrap
本身具有相同功能! 我們可以進一步擴展它...
class permission_check_wrapper:
def __init__(self, function, permission):
self.function = function
self.permission = permission
functools.update_wrapper(self, function)
def __call__(self, *args, **kwargs):
if not current_user.can(permission):
abort(403)
return function(*args, **kwargs)
class permission_required:
def __init__(self, permission):
self.permission = permission
def __call__(self, function):
return permission_check_wrapper(self.permission, function)
或者我們可以使用functools.partial
完成整個工作:
def permission_check_wrapper(*args, function, permission, **kwargs):
if not current_user.can(permission):
abort(403)
return function(*args, **kwargs)
def wrap_fn_with_permission_check(function, *, permission):
return functools.update_wrapper(
functools.partial(permission_check_wrapper,
function=function,
permission=permission),
wrapped=function)
def permission_required(permission):
return functools.partial(wrap_fn_with_permission_check,
permission=permission)
定義@decorator(a,b,c) def foo
以將@decorator(a,b,c) def foo
foo = decorator(a,b,c)(foo)
@decorator(a,b,c) def foo
在於,該語言不在乎您選擇這幾種實現技術中的哪一種。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.