编辑/澄清以使我的问题特定于我的查询: *我可以看到如何调用装饰器静态日志函数,但我没有看到如何调用 _ 以及它的结果如何是日志的结果。我可以看到输入/输入内容的工作原理*
class logger:
@staticmethod
def log(func):
def ___(*args, **kwargs):
try:
print "Entering: [%s] with parameters %s" % (func.__name__, args)
try:
return func(*args, **kwargs)
except Exception, e:
print 'Exception in %s : %s' % (func.__name__, e)
finally:
print "Exiting: [%s]" % func.__name__
return ___
class x:
@logger.log
def first_x_method(self):
print 'doing first_x_method stuff...'
x().first_x_method()
给出了这个输出:
Entering: [first_x_method] with parameters (<__main__.x instance at 0x0000000001F45648>,)
doing first_x_method stuff...
Exiting: [first_x_method]
我可以看到logger是一个带有静态方法的类,用于装饰(@logger.log
)first_x_method。
但是我不明白为什么调用___
子方法(可以是任何名称)。
答案 0 :(得分:5)
装饰者的基本事实是
@decorator
def func(): ...
完全等同于
def func(): ...
func=decorator(func)
所以,
@logger.log
def first_x_method(self): ...
与
相同def first_x_method(self): ...
first_x_method=logger.log(first_x_method)
因此使用参数logger.log
调用func = first_x_method
静态方法。
在对logger.log(first_x_method)
的调用中,定义并返回子方法__
。
first_x_method=logger.log(first_x_method)
因此设置first_x_method
以引用子方法__
。
first_x_method()
中的括号告诉Python调用方法first_x_method
。
因此x().first_x_method()
首先实例化类x的实例,然后调用方法first_x_method
(提供x()作为第一个参数)。
由于first_x_method
引用__
,因此__
被调用。
答案 1 :(得分:2)
装饰器是一个函数,它接受一个函数作为参数,并返回一个“装饰”函数,该函数在被调用时实际使用。
在这种情况下,logger.log
传递函数first_x_method
。实际的装饰器实现创建了一个函数,该函数在运行其参数之前和之后打印消息,并返回该函数(在本例中,称为___
)。因此,实际上,每次拨打first_x_method
时,您实际上都在调用____
,其中first_x_method
的引用保持为func
。
换句话说,____
“捕获”first_x_method
并替换它。每当它被调用时,它将首先打印一些东西,调用它有引用的函数,然后再打印一些东西。
编辑:也许这个简化的例子可以帮助你理解它:
def decorate(func):
print "Decorate called"
def internal(*args, **kwargs):
print "Calling internal"
func(*args, **kwargs)
print "Original function returned: "
print "Created the decorated function, returning."
return internal
@decorate
def foo(s):
print "foo called with: ", s
return 42
foo('hello')
答案 2 :(得分:1)
def decorate(fn):
def wrapper():
fn()
print 'Wrapping function ', wrapper
return wrapper
def x():
pass
print 'Original x ', x
x = decorate(x)
print 'New x ', x
输出:
Original x <function x at 0x7f3c51e9a758>
Wrapping function <function wrapper at 0x7f3c51e9a7d0>
New x <function wrapper at 0x7f3c51e9a7d0>
请注意x
现在与wrapper
的相同之处。当您致电x
时,您实际上正在呼叫wrapper
。
不要将此答案标记为答案。将其中一个标记为答案。这样做的目的是纠正一个误解,这样你就可以正确地理解其中一个答案。