Decorators are syntactic sugar for applying higher-order functions in Python. A higher-order function is a function that takes one or more functions as inputs and returns a function. i.e.
h(x) = f(g(x))
where here f()
is a higher-order function that takes a function of a single argument, g(x)
, and returns a function of a single argument, h(x)
. You can think of f()
as modifying the behaviour of g()
.
Higher-order functions are composable (by definition), so in your specific example, the decorator syntax,
@helloGalaxy
@helloSolarSystem
def hello(targetName=None):
...
is equivalent to,
hello = helloGalaxy(helloSolarSystem(hello))
By substituting hello
into helloSolarSystem
, then the result of that into helloGalaxy
, we get the equivalent function call,
def hello(targetName=None):
if targetName: |
print("Hello, " + targetName + "!") | (1) |
else: | | (2) |
print("Hello, world!") | | | (3)
print("Hello, solar system!") | |
print("Hello, galaxy!") |
where (1) is the application of the original hello()
, (2) is the application of,
def helloSolarSystem(original_function):
def new_function(*args, **kwargs):
original_function(*args, **kwargs) <-- (1)
print("Hello, solar system!")
return new_function
and (3) is the application of,
def helloGalaxy(original_function):
def new_function(*args, **kwargs):
original_function(*args, **kwargs) <-- (2)
print("Hello, galaxy!")
return new_function