This library provides a simple interface for changing the behavior of existing function/method objects.
Download: pycodeutils.zip (License: MIT License, see file LICENSE
in the distribution)
The behavior of a function/method object is changed by replacing its associated code object with a new one. The new code object delegates the execution to a given user-defined function (delegatee). The arguments as well as the original code are passed to the delegatee. So it is possible to either execute additional code before/after the original code or to replace the original code completely.
# New behaviour def delegatee(f, args, kw): ... # Change behavior of function my_func from codeinst import delegate_code delegate_code(my_func, delegatee)
The following example changes the behavior of two methods of Python’s standard Template
class so that an additional substitution dictionary is used.
# Import advise function of the code instrumentation library from codeinst import delegate_code from string import Template # Define your new behaviour global_subst_kws = {'x': 'X'} def substitute_delegatee(f,args,kw): kw.update(global_subst_kws) return f(*args,**kw) # Apply the new behavior to Template's substitution methods delegate_code([Template.substitute, Template.safe_substitute], substitute_delegatee) # Test the new behavior print Template("$x and $y").substitute({'x': '1', 'y': '2'}) # => X and 2 print Template("$x and $z").safe_substitute({'z': '3'}) # => X and 3
The delegatee is a function with the signature delegatee(f, args, kw)
:
f
: Function object representing the original code1)args
: Tuple containing the positional arguments followed by the variable argumentskw
: Dictionary containing the remaining keyword arguments (i.e. the keyword arguments which could not be bound to positional arguments of f
).
You can call f
whenever you want to use the original function. You can change the arguments. It is even possible to call f
several times. If you just want to proceed with the original behavior, you can use f(*args,**kw)
(don’t forget to return the value).
Note that replacing the code object is different from wrapping a function object. A wrapper is a complete new function object which encapsulates the original function. However, because it is a new object, the effect of the wrapper is only local. Already established references to the function object (e.g. in other modules) still refer to original function.
Contrariwise, by means of replacing the code object, the function object itself remains the same. The new code object is in effect for all existent references to the function.
Only modifications to plain functions and unbound methods are allowed. Trying to instrument a bound method (i.e. a method already associated with a particular self
instance) will raise a TypeError
. This is intentional.
Furthermore, built-in functions and methods are not supported because they do not provide a code object.
f
representing the original code is created each time the function is invoked.