[英]Python Class Based Decorator with parameters that can decorate a method or a function
我見過很多 Python 裝飾器的例子,它們是:
__init__
、 __get__
和__call__
)但是我從未見過可以完成上述所有操作的單個示例,而且我無法從特定問題的各種答案(例如this one 、 this one或this one (具有最佳答案之一)進行綜合)我曾經在 SO) ) 上看到過如何將上述所有內容結合起來。
我想要的是一個基於類的裝飾器,它可以裝飾一個方法或一個函數,並且至少需要一個額外的參數。 即,以便以下工作:
class MyDecorator(object):
def __init__(self, fn, argument):
self.fn = fn
self.arg = argument
def __get__(self, ....):
# voodoo magic for handling distinction between method and function here
def __call__(self, *args, *kwargs):
print "In my decorator before call, with arg %s" % self.arg
self.fn(*args, **kwargs)
print "In my decorator after call, with arg %s" % self.arg
class Foo(object):
@MyDecorator("foo baby!")
def bar(self):
print "in bar!"
@MyDecorator("some other func!")
def some_other_function():
print "in some other function!"
some_other_function()
Foo().bar()
我希望看到:
In my decorator before call, with arg some other func!
in some other function!
In my decorator after call, with arg some other func!
In my decorator before call, with arg foo baby!
in bar!
In my decorator after call, with arg foo baby!
編輯:如果重要的話,我使用的是 Python 2.7。
你不需要弄亂描述符。 在__call__()
方法中創建一個包裝函數並返回它就足夠了。 標准 Python 函數始終可以充當方法或函數,具體取決於上下文:
class MyDecorator(object):
def __init__(self, argument):
self.arg = argument
def __call__(self, fn):
@functools.wraps(fn)
def decorated(*args, **kwargs):
print "In my decorator before call, with arg %s" % self.arg
result = fn(*args, **kwargs)
print "In my decorator after call, with arg %s" % self.arg
return result
return decorated
關於當這個裝飾器這樣使用時發生了什么的一些解釋:
@MyDecorator("some other func!")
def some_other_function():
print "in some other function!"
第一行創建了一個MyDecorator
的實例並傳遞了"some other func!"
作為__init__()
的參數。 讓我們稱這個實例為my_decorator
。 接下來,未裝飾的函數對象——讓我們稱之為bare_func
被創建並傳遞給裝飾器實例,因此my_decorator(bare_func)
被執行。 這將調用MyDecorator.__call__()
,它將創建並返回一個包裝函數。 最后這個包裝函數被分配給名稱some_other_function
。
你缺少一個級別。
考慮代碼
class Foo(object):
@MyDecorator("foo baby!")
def bar(self):
print "in bar!"
它與此代碼相同
class Foo(object):
def bar(self):
print "in bar!"
bar = MyDecorator("foo baby!")(bar)
所以MyDecorator.__init__
被調用為"foo baby!"
然后使用函數bar
調用MyDecorator
對象。
也許你的意思是實現更像
import functools
def MyDecorator(argument):
class _MyDecorator(object):
def __init__(self, fn):
self.fn = fn
def __get__(self, obj, type=None):
return functools.partial(self, obj)
def __call__(self, *args, **kwargs):
print "In my decorator before call, with arg %s" % argument
self.fn(*args, **kwargs)
print "In my decorator after call, with arg %s" % argument
return _MyDecorator
在您的裝飾器類型列表中,您錯過了可能帶參數也可能不帶參數的裝飾器。 我認為這個例子涵蓋了除“函數風格裝飾器(包裝函數)”之外的所有類型
class MyDecorator(object):
def __init__(self, argument):
if hasattr('argument', '__call__'):
self.fn = argument
self.argument = 'default foo baby'
else:
self.argument = argument
def __get__(self, obj, type=None):
return functools.partial(self, obj)
def __call__(self, *args, **kwargs):
if not hasattr(self, 'fn'):
self.fn = args[0]
return self
print "In my decorator before call, with arg %s" % self.argument
self.fn(*args, **kwargs)
print "In my decorator after call, with arg %s" % self.argument
class Foo(object):
@MyDecorator("foo baby!")
def bar(self):
print "in bar!"
class Bar(object):
@MyDecorator
def bar(self):
print "in bar!"
@MyDecorator
def add(a, b):
print a + b
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.