这个python装饰器是如何工作的?

时间:2011-03-30 04:03:17

标签: python decorator

编辑/澄清以使我的问题特定于我的查询: *我可以看到如何调用装饰器静态日志函数,但我没有看到如何调用 _ 以及它的结果如何是日志的结果。我可以看到输入/输入内容的工作原理*

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。

但是我不明白为什么调用___子方法(可以是任何名称)。

3 个答案:

答案 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

不要将此答案标记为答案。将其中一个标记为答案。这样做的目的是纠正一个误解,这样你就可以正确地理解其中一个答案。