A decorator is a higher-order function which takes a function as input and returns a function as output. Decorator syntax is a way of calling this higher order function.
The lines
@register
def f1():
print('running f1()')
are equivalent to the lines
def f1():
print('running f1()')
f1 = register(f1)
Usually, the decorator modifies the decorated function. In this case it is returned unmodified. But -- it is still returned. If the decorator returned nothing then the decorator would replace f1
by None
(which wouldn't be very useful). This particular decorator is called for its side effects (registering a function). The fact that it returns an unmodified function doesn't mean that it isn't called.
The output that you see should make sense now:
running register(<function f1 at 0x0000000001DCCBF8>)
running register(<function f2 at 0x0000000003566D90>)
running main()
registry -> [<function f1 at 0x0000000001DCCBF8>, <function f2 at 0x0000000003566D90>]
running f1()
running f2()
running f3()
You used @register
twice, which calls register()
twice, before main is run. Neither f1
nor f2
were actually changed by the decorator, hence they work as expected when called in main()
. The printed value of registry
shows that the decorator worked as intended: it registered the decorated f1, f2
but didn't register the undecorated f3
.
On the other hand, if you remove the line return func
from the decorator, you see (something like):
running register(<function f1 at 0x00000000004DCBF8>)
running register(<function f2 at 0x0000000003586D90>)
running main()
registry -> [<function f1 at 0x00000000004DCBF8>, <function f2 at 0x0000000003586D90>]
Traceback (most recent call last):
File "C:\Users\jcoleman\Documents\Programs\PythonScripts\socode.py", line 68, in <module>
main()
File "C:\Users\jcoleman\Documents\Programs\PythonScripts\socode.py", line 64, in main
f1()
TypeError: 'NoneType' object is not callable
The decorator is still called twice -- but they are now (implicitly) returning None
. As soon as f1()
is hit in main
you get a run-time error since at that stage f1
is None
, which isn't callable.
See this question for more on decorators.