To use the library constructors, add this import line:
import dectools
Use a constructor as decorator on your function. Your function must have the correct function signature: the first argument must be “function” and the second and third arguments are probably “args” and “kwargs”. Put any additional arguments after these required arguments.
TODO: Make these arguments optional, because only @make_call_instead really needs them.
For example:
@make_call_before
def my_new_call_before_decorator(function, args, kwargs, some_other_argument):
# do stuff
....
@my_new_call_before_decorator("foo") # or (some_other_argument = "foo")
def my_newly_decorated_function(other_args):
pass
We will call “my_new_call_before_decorator” the decorator and “my_newly_decorated_function” the decorated function.
Construtor | Required Parameters | Used For |
---|---|---|
@make_call_once | function | registering with frameworks, global resource creation |
@make_call_before | funciton, args, kwargs | requiring login, lazy instantiation |
@make_call_if | function, args, kwargs | checking priviledges, skipping if overloaded |
@make_call_after | function, args, kwargs | converting return values to exceptions, redrawing the screen |
@make_call_instead | function, args, kwargs | everything else. logs, caches, locking, resource handling. |
Requires: (function, ...)
Call the decorator once when the decorator is applied, but does not affect the decorated function.
Used for registering the function with frameworks, global resource creation, or enforcing proprietary licensing restrictions.
Requires: (function, args, kwargs, ...)
Call the decorator before the decorated function, then call the decorated function. If the decorator throws an exception, then the decorated function is not called.
Used for requiring users to be logged in first, lazy instantiation of resources, and setting preconditions.
Requires: (function, args, kwargs, ...)
Call decorator after the decorated function. The decorator’s return value is returned.
Used for converting errors from return values into exceptions, double checking that resources were released, and redrawing of the screen.
Requires: (function, args, kwargs, ...)
Call decorator first. If decorator returns a True value, then call the decorated function.
Used for checking authorization, skipping decluttering during peak times, and enforcing some proprietary licensing.
Requires: (function, args, kwargs, ...)
Call the decorator. Do not call the decorated function. The decorator will usually call the function with the statement return_value = function(*args, **kwargs).
Used for everything, including logging, caching, acquiring and releasing locks, acquiring and releasing other resources, comparing results between an optimized algorithm and a slow but reliable one, and more.
TODO: Make the constructors really work this way instead of with a couple extra levels of functino calls. The concept is about right.
This follows through one example to show how it works. Walking through it might demystify decorators, might make you think I am an idiot, and might put you to sleep.
@make_call_instead # Step 1
def notice_me(function, args, kwargs, message = "I see you"):
print message + ": " + function.__name__
return function(args, kwargs)
@notice_me("Watching you") # Step 2, Parts A and B.
def hello(name):
print "Hello", name
hello("Charles") # Step 3.
This is the same example, except we do some extra assignements to temporary or differently-named variables. It also moves the @ operation to after the def statement, which is where it actually occurs.
def notice_me(function, args, kwargs, message = "I see you"):
print message + ": " + function.__name__
return function(args, kwargs)
widget = make_call_instead(notice_me) # Step 1
notice_me = widget
def hello(name):
print "Hello", name
gizmo = widget("Watching you") # Step 2 Part A
hello_out = gizmo(hello) # Step 2 Part B
hello = hello_out
hello("Charles") # Step 3
The constructor, @make_call_instead, is a concrete decorator because it takes one function as input. The function passed in, e.g., notice_me():
The return value, named widget here, has some properties:
Step 2 is divided into two parts, because two separate operations occur in the line @notice_me(“Watching you”). notice_me(“Watching you”) resolves into an intermediate value and the ‘@’ operation is then applied.
For Part A., gizmo = widget(“Watching you”) takes an argument.
This line, “hello_out = gizmo(hello)” decorates hello.
When the line hello(“charles”) is called these things happen:
hello(“charles”) is called. When it was decorated, the actual code for hello was changed to call a dectools function. Let’s call this function “call_through()” for this example.
“call_through()” then calls notice_me() with the original hello function and additonal decorator parameters. In this case, it’s called:
notice_me(function= hello, args = ("charles"), kwargs = {}, message = "Watching you")
notice_me() then prints “Watching you: hello”, then calls hello. I wonder if anyone reads this documentation? Email me if you do.
The return value of hello() is returned to notice_me() which is returned to call_through() which is returned to the main program, where it is ignored.