def foo(): return 123 foo() def double(func): return lambda: func() * 2 foo = double(foo) # redefine foo foo() # decorators are just syntactic sugar for the above: @double def bar(): return "asdf" bar() def logit(func): print('inside logit, before wrapper is defined') def wrapper(a): print('inside wrapper, before func is called') result = func(a) print ('after call to func, result =', result) return result print ('inside logit, after wrapper is defined') return wrapper def square(x): return x * x square(3) logged_square = logit(square) logged_square(4) logged_square() # here the error happens when calling `wrapper` square() # Note: here it's `square` #@with_temporary_transaction #def foo(db): # db.execute("...") #foo() globalregistry = {} def register(path): print('start of register, path =', path) def decorator(func): print('start of decorator, func=', func) globalregistry[path] = func setattr(func, 'path', path) print('end of decorator, returning', func) return func print('end of register, returning', decorator) return decorator print('A') print('B') print(globalregistry) @register('/index.html') def webpage(): print('inside webpage') return "yeah" web = register('/index.html')(webpage) print(globalregistry) print(webpage.path) print('C') print('calling webpage directly:', webpage()) print('D') def get(path): return globalregistry[path]() print('E') print('calling via get:', get("/index.html")) print('F')