简体   繁体   中英

why can the decorator function lack the f parameter?

UPDATE :

class Flask():
 def route(self,rule,**options):#why here doesn't exist a paramter to receive the decorated function?
    def wrapper(f):
        endpoint = options.pop('endpoint',None)
        self.add_url_rule(rule,endpoint,f,**option)
        return f
    return wrapper

@app.route('/grade',methods=['post'])
def example():
        pass

why doesn't the route function have got a parameter to receive decorated function -- example

just like what the typical example does to use decorator in python

def my_decorator(f):# the my_decorator function has got a parameter to receive  the decorated function

     def wrapper(*args, **kwds):
         print('Calling decorated function')
         return f(*args, **kwds)
     return wrapper

@my_decorator
def example():
     """Docstring"""
     print('Called example function')

It is maybe a not-naive concept, but to build a decorator with parameters you are coding a decorator that generates a decorator . To get you there let me spend a couple of words.

In the case of a simple decorator you are usually going the way you are reporting:

def decorator(function):
    def wrapper(*args, **kwargs):
        print("bar")
        function(*args, **kwargs)
    return wrapper

@decorator
def foo(word):
    print(word)

foo('boo')

result

"bar"
"boo"

where foo gets executed inside wrapper as the 'value' of the variable function , which is assigned by mean of the annotation @decorator itself -without input.

Given this, in case you want to have also decorator inputs, you need to issue another level, catching the input and wrapping it into a closure - which is the actual declaration of the decorator, wrapping the function. That's what happens in flask code.

def decorator_factory(*a, **kw):
    def decorator(function):
        def wrapper(*args, **kwargs):
            print(a[0])
            function(*args, **kwargs)
        return wrapper
    return decorator

@decorator_factory('bar')
def foo(word):
    print(word)

foo('boo')

results again in

"bar"
"boo"

It's not the Flask.route function that receives the decorated function, but the one called decorator . That's how you can give the routing rules to the decorator with an extra function call. If you look closely, you will see that your example of "a typical decorator" is broken in multiple places, thus is a wrong example to compare with. After fixing the compilation errors it gives the following runtime error:

def decorator(func):
  def wrapper():
    x = func()
    return x
  return wrapper

@decorator()
def balabala():
  pass

...

TypeError: decorator() missing 1 required positional argument: 'func'

This is because you call it without an argument.

A decorator defined this way is not meant to be used with parentheses, the right way would be:

@decorator # no brackets here
def balabala():
  pass

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM