function-objects and code-objects ( was: re-creating objects and security )

Steven D. Majewski (sdm7g@elvis.med.virginia.edu)
Wed, 31 Aug 1994 19:06:23 -0400

[ Dave Brennan asked about about the difference between
function objects and code objects. ]

This is incomplete. I don't have time to comb thru the sources
to look for what I don't know or can't remember, but maybe an
incomplete reply will remind me to try to attempt a more complete
writeup later.

Both function-objects and code-objects are composite objects.

>>> def f(x) : return x
>>> f
<function f at 20068e98>
>>> f.__members__
['func_argcount', 'func_argdefs', 'func_code', 'func_globals', 'func_name']

I'm not too sure about the values and mechanics of the first two.
f.func_argdefs is used to implement the default value mechanism.
( def f( x, a=1 ): return x+a )

f.func_globals is the namespace for globals references in the function.
In a function defined in a module, it would be the modules __dict__ ;
interactively, it's the __main__ module's __dict__.

f.func_name is just the name string ( 'f' )

f.func_code is the function's code-object.

>>> f.func_code
<code object f at 20071da8, file "<stdin>", line 1>
>>> f.func_code.__members__
['co_code', 'co_consts', 'co_filename', 'co_name', 'co_names']

f.func_code.co_code is the actual string containing the byte-code
for the Python virtual machine interpreter.

f.func_code.co_name is the name string. ( which is most cases will
be the same as the function name. )

f.func_code.co_filename is the filename of the module the code
function was defined in, or '<stdin>' for interactively defined
code.

[ The above two are used when printing error messages, and by
debuggers and disassemblers. ]

f.co_consts is a list containing any constants use in the code and
a dictionary that maps argument names to argument number.

f.co_names is a list of names. [ I don't recall offhand how these
two interact. ]

So a code *STRING* is a sequence of instructions or py-opcodes.
A code *OBJECT* is a code string plus constants and locals and
some other context.
A function object is a code object and some other context to map
arguments and globals and to check that functions are called
with the correct number of arguments.

'exec' takes either a string, an open file, or a code object,
and optionally a global and local dict/namespace.

A single marshaled code object is what .py files contain,
and import exec's that object in a brand new modules dictionary.
As a side-effect, that dictionary is filled with the objects
defined in the module.

But note that you can't just exec a function or methods code object:
a function has instructions to unpack and return arguments.
The code object produced by "compile( 'x+1', '', 'exec' )", for
example, doesn't. And since exec has no way to pass an argument
list ( and apply expects a function or method, not a code object. )
it requires non-function code.

If you detect some redundancies in the above account, or a suspicion
that some of these attributes are not in the "right" place, it may
be due to the gradual evolution of the system ( and Guido's effort
not to break anything without good reason. ). On the other hand -
this is from my poor memory and peeking at __members__ from the
interpreter. [ I have notes somewhere that I produced when hacking
ceval.c to try to add coroutine support. ]

See Tommy Burnette's newobject module for a way to re-wrap code
objects into new function-objects. ( I posted some ugly hacks to
do similar things before he wrote that module. )

See Object/funcobject.c for the internals of function objects and
code objects.

See Python/ceval.c for a look at what the interpreter does with these
objects.

See comp.lang.python archive for some old discussions like the one
about coroutines and continuations - that explains what's in a
frame objects and how it's almost a continuation. I still have
hacks in my ceval.c code that implements semi-coroutines by storing
a little more context in frameobjects and making them restartable.
Another promising thread dropped due to lack of time! :-(

[ I'm secretly half hoping that adding meta-classes will cause
Guido to change the internals sufficiently that he'll make
Matt Conway the new nominee to write a Python internals manual,
and I'll weasle out of a demi-semi-hemi-promise to start one! :-) ]

- Steve Majewski (804-982-0831) <sdm7g@Virginia.EDU>
- UVA Department of Molecular Physiology and Biological Physics