开发者

How does this python decorator work?

Edit/Clarification to make my question specific to my query: *I can see how the decorator static log function is called but I don't see how _ is called and how the result of it is the result of log. I cam see how the entry/enter stuff works*

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()

gives this output:

Entering: [first_x_method] with parameters (<__main__.x instance at 0x0000000001F45648>,)
doing first_x_method stuff...
Exiting: [first_x_method]

I can开发者_运维问答 see that logger is a class with a static method that is used to decorate (@logger.log) first_x_method.

However I don't understand why the ___ sub method (and it can be any name) is called.


The fundamental fact about decorators is that

@decorator
def func(): ...    

is exactly equivalent to

def func(): ...
func=decorator(func)

So,

@logger.log
def first_x_method(self): ...

is the same as

def first_x_method(self): ...
first_x_method=logger.log(first_x_method)

and so the logger.log static method is called with argument func = first_x_method.

Inside the call to logger.log(first_x_method), the sub method __ is defined and returned.

first_x_method=logger.log(first_x_method) thus sets first_x_method to refer to the sub method __.

The parenthesis in first_x_method() tells Python to call the method first_x_method.

So x().first_x_method() first instantiates an instance of the class x, and then calls the method first_x_method (with x() supplied as the first argument).

Since first_x_method refers to __, it is __ that gets called.


A decorator is a function that accepts a function as an argument and returns a "decorated" function that will actually be used when it's called.

In this case logger.log is passed the function first_x_method. The actual decorator implementation creates a function that prints a message before and after running its argument, and returns that function (in this case, called ___). So in effect, every time you call first_x_method, you're actually calling ____, which maintains a reference to first_x_method as func.

In other words, ____ "captures" first_x_method and replaces it. Whenever it's called, it will first print something, call the function it has a reference to, and then print something again.

edit: Maybe this simplified example can help you understand it:

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')


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

Output:

Original x <function x at 0x7f3c51e9a758>
Wrapping function <function wrapper at 0x7f3c51e9a7d0>
New x  <function wrapper at 0x7f3c51e9a7d0>

Note how x is now the same as wrapper. When you call x, you are actually calling wrapper.

Do not mark this answer as the answer. Mark one of the others as the answer. The point of this is to correct a misunderstanding so that you may then correctly understand one of the other answers.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜