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
Removing Entries from a Dictionary Based on Values
Accessing CPU Temperature in Python
How to Create an SQL View with SQLalchemy
Mixed Slashes with Os.Path.Join on Windows
Regex: Attributeerror: 'Nonetype' Object Has No Attribute 'Groups'
Python: Catching Specific Exception
Understanding .Get() Method in Python
Duplicate Items in Legend in Matplotlib
Python Selenium: Wait Until Element Is Clickable - Not Working
Xrange(2**100)' -> Overflowerror: Long Int Too Large to Convert to Int
Distributing My Python Scripts as Jar Files with Jython
Python Ungzipping Stream of Bytes
Overwriting File in Ziparchive
Is There a Recursive Version of the Dict.Get() Built-In