Decorator Execution Order

Decorator execution order

Decorators wrap the function they are decorating. So make_bold decorated the result of the make_italic decorator, which decorated the hello function.

The @decorator syntax is really just syntactic sugar; the following:

@decorator
def decorated_function():
# ...

is really executed as:

def decorated_function():
# ...
decorated_function = decorator(decorated_function)

replacing the original decorated_function object with whatever decorator() returned.

Stacking decorators repeats that process outward.

So your sample:

@make_bold
@make_italic
def hello():
return "hello world"

can be expanded to:

def hello():
return "hello world"
hello = make_bold(make_italic(hello))

When you call hello() now, you are calling the object returned by make_bold(), really. make_bold() returned a lambda that calls the function make_bold wrapped, which is the return value of make_italic(), which is also a lambda that calls the original hello(). Expanding all these calls you get:

hello() = lambda : "<b>" + fn() + "</b>" #  where fn() ->
lambda : "<i>" + fn() + "</i>" # where fn() ->
return "hello world"

so the output becomes:

"<b>" + ("<i>" + ("hello world") + "</i>") + "</b>"

Python decorator to determine order of execution of methods

If you are using Python 3.6, this is a case that can take advantage of the new __init_subclass__ method. It is called on the superclass by subclasses when they are created.

Withut Python3.6 you have to resort to a metaclass.

The decorator itself can just mark each method with the needed data.

def on_initialize(precedence=0):
def marker(func):
func._initializer = precedence
return func
return marker

def on_event(precedence=0):
def marker(func):
func._event_handler = precedence
return func
return marker

def on_finalize(precedence=0):
def marker(func):
func._finalizer = precedence
return func
return marker

class Framework:

def __init_subclass__(cls, *args, **kw):
super().__init_subclass__(*args, **kw)
handlers = dict(_initializer=[], _event_handler=[], _finalizer=[])
for name, method in cls.__dict__.items():
for handler_type in handlers:
if hasattr(method, handler_type):
handlers[handler_type].append((getattr(method, handler_type), name))

for handler_type in handlers:
setattr(cls, handler_type,
[handler[1] for handler in sorted(handlers[handler_type])])

def initialize(self):
for method_name in self._initializer:
getattr(self, method_name)()

def handle_event(self, event):
for method_name in self._event_handler:
getattr(self, method_name)(event)

def finalize(self):
for method_name in self._finalizer:
getattr(self, method_name)()

def run(self):
self.initialize()

for event in range(10):
self.handle_event(event)

self.finalize()

If you will have a complex class hierarchy that should inherit the action methods properly, you wll have to merge the lists in the handlers dictionary with the ones in the superclass (get the superclass as cls.__mro__[1]) before applying then as class attributes.

Also, if you are using any Python < 3.6, you will need to move the logic on __init_subclass__ to a metaclass. Just put the code as it is on the __init__ method of a metaclass (and adjust the incoming parameters and super call as apropriate), and it should work just the same.

Does the order of decorators matter on a Flask view?

While there probably won't be any problem in this case no matter what the order, you probably want login_required to execute first so that you don't make queries and paginate results that will just get thrown away.

Decorators wrap the original function bottom to top, so when the function is called the wrapper added by each decorator executes top to bottom. @login_required should be below any other decorators that assume the user is logged in so that its condition is evaluated before those others.

@app.route() must always be the top, outermost decorator. Otherwise the route will be registered for a function that does not represent all the decorators.


The broader answer is that it depends on what each of the decorators are doing. You need to think about the flow of your program and whether it would make logical sense for one to come before the other.

What is the decorator running order?

The decorator expressions get called top to bottom, and produce decorators.


The decorators themselves run in the opposite direction, bottom to top:

@a @b x
// bit like
{
const decA = a
const decB = b
decA(decB(x))
}

In your example

{
const decComp = Component({selector: 'person', template: 'person.html'})
// selector: person
// template: person.html
// component init
const decDirective = Directive()
// directive init
decComp(decDirective(Person))
// directive call
// component call
}

Reference

What is the order of execution for method decorators?

In what order will foo and bar be executed?

In order of appearance. So foo then bar.

What's the logical execution order of this Python decorated function?

The decorator is only executed once. It takes a callable object and returns a callable object. The object that it returns is used in place of a1.

In other words, b1 is called at the point where a1 is defined. It prints out "b1" and returns a1 unchanged. Since it returns a1 unchanged, b1 plays no role whatsoever in any subsequent calls to a1.

Therefore, the following comment isn't quite correct:

  a1() # will print b1 a1

In fact,

  • a1() only prints "a1".
  • The "b1" that you see is printed by @b1 / def a1():.

If you change the code like so and re-run, the sequence of events should become clearer:

def b1(fnc):
print "b1"
return fnc

@b1
def a1():
print "a1"

if __name__ == "__main__":
print 'in __main__'
a1()
a1()

Finally, to achieve the effect you were looking for, the decorator would need to return a different callable object:

def b1(fnc):
def decorated():
print "b1"
return fnc()
return decorated

@b1
def a1():
print "a1"

if __name__ == "__main__":
print 'in __main__'
a1()
a1()

Here, it is pretty clear who is calling fnc().

Controlling the order in which typescript property decorators are applied?

The decorator should not have a dependency on the usage order.
They should be all standalone and work independently.

In this case, the @IsGreaterThan should have @IsNumber used internally to ensure the target is a number.

On the other hand, controlling the order is easy. The closest is applied first. So in your case, you need

class Product {
@IsGreaterThan('purchasePrice')
@IsPositive
@IsNumber
salesPrice: number
}

Decorator is just a sugar of a descriptor function, which is a higher order function like this:

function IsNumber(target, key, descriptor) { ... }

So the code above is actually just (pseudo code):

class Product {
salesPrice = IsGreaterThan('puchasePrice')(IsPositive(IsNumber(Product, 'salesPrice')))
}

Since the class syntax is a sugar itself, the code above looks weird as I just trying to show you the underlying concept.

Multiple decorators for a view in Django: Execution order

Now, the decorators in Python work from the inside out

Well I guess that depends on your definition of inside out. In your case, you want @login_required to execute first, and so it should be the "outermost" (top) decorator.

As you noted, your last example works, and is indeed the correct way to do this.

edit

The confusion might be how these particular decorators work.

@login_required(@original_view) returns a new view, which first checks if you are logged in, and then calls original_view

so


@login_required(
@active_required(
@my_view
)
)
first checks if you are logged in, then
first(second) checks if you are active, then
runs my_view


Related Topics



Leave a reply



Submit