[Tutor] Writing decorators?
Steven D'Aprano
steve at pearwood.info
Wed Jul 20 14:54:33 EDT 2016
On Wed, Jul 20, 2016 at 03:30:43PM +0200, Michael Welle wrote:
> > It [a decorator]
> > can modify the function and return it,
>
> Now it gets interesting ;). Can you give me a hint on how to modify the
> code of the function in a decorator or even give a small example,
> please? Would I take the route with the bytecode attribute __code__
> (IIRC)? Or use the inspect module?
The inspect module is not really designed for changing objects, only for
inspecting them. (Reading, not writing.)
Function code objects are immutable, so you cannot change them in place,
only replace them with a new code object:
py> def f():
... print("f")
...
py> def g():
... print("g")
...
py> f()
f
py> f.__code__ = g.__code__
py> f()
g
The code object itself is very complex, and badly documented:
py> help(f.__code__)
Help on code object:
class code(object)
| code(argcount, kwonlyargcount, nlocals, stacksize, flags, codestring,
| constants, names, varnames, filename, name, firstlineno,
| lnotab[, freevars[, cellvars]])
|
| Create a code object. Not for the faint of heart.
so in practice the way to create them is by actually defining a
function, then extracting its __code__ object. But if you're going to do
that, why not just use the function?
There are a couple of projects designed to let you manipulate the
byte-code of functions, but because the byte-code format is not part of
the public Python API, it tends to change from version to version. If
you use the wrong byte-code, you can crash the interpeter and cause a
segmentation fault or core dump.
However, there is some talk about creating a interface to modify a
function's abstract syntax tree. At the moment consider that to be just
talk, but its more likely than a supported interface to edit byte-code.
But for those brave, or silly, enough, here are some resources for
editing byte-code to get you started:
http://www.voidspace.org.uk/python/articles/code_blocks.shtml
https://wiki.python.org/moin/ByteplayDoc
There are ways to modify functions apart from changing their code. For
example, you can change argument defaults, add attributes to the
function object, change the global namespace that the function works
with. I have an experimental project that modifies functions so that
instead of searching for variables in this order:
locals
nonlocals
globals
builtins
it uses:
locals
nonlocals
custom namespace set by the user
globals
builtins
(Technically, I don't "modify" the function, since some parts of the
function are immutable and cannot be changed. Instead I replace it with
a new function, copied from the original but with a slight
modification.)
If you are interested in that, see the discussion that starts here:
https://mail.python.org/pipermail/python-list/2016-July/711177.html
The original version of the code I gave uses a metaclass; the version I
have now also supports being called as a decorator.
--
Steve
More information about the Tutor
mailing list