dynamic function names

Alex Martelli aleax at aleax.it
Mon Apr 28 07:28:53 EDT 2003


Duncan Booth wrote:

> Alex Martelli <aleax at aleax.it> wrote in
> news:iP5ra.14084$3M4.382689 at news1.tin.it:
> 
>> See?  "def funcname():" *RE-BINDS* identifier funcname to
>> refer to the function object.
>> 
>> So, what you need is to call function 'function' in module
>> 'new'.  You can first build a temporary function with a def
>> to give you the right code, globals, defaults and closure,
>> and then pass each of these to new.function together with
>> the funcname you want to use:
>> 
>>>>> import new
>>>>> def makefunc(funcname):
>> ...   def temp(): print "this function is named", funcname
>> ...   f = new.function(temp.func_code, globals(), funcname,
>> ...           temp.func_defaults, temp.func_closure)
>> ...   return f
>> ...
>>>>> f = makefunc('foo')
>>>>> f()
>> this function is named foo
>>>>> f.func_name
>> 'foo'
> 
> Note that this code only works on Python 2.3 (because the closure argument
> to new.function didn't exist earlier), and even there if the function
> 'foo' throws an exception the traceback will still call it 'temp'.

Very good points, thanks!  Of course, they can be fixed -- but you
need to prepare a new suitable code-object rather than just reuse
the one from 'temp'.  It's just a bit longer, because a code object
has a LOT of attributes you must pass to make a new one;-).

Given this, I would factor this a bit differently:

import new

def make_named_func(name, func=None):
    if func is None:
        def func(*args): return args
    c = func.func_code
    nc = new.code(c.co_argcount, c.co_nlocals, c.co_stacksize, c.co_flags,
        c.co_code, c.co_consts, c.co_names, c.co_varnames, c.co_filename,
        name,
        c.co_firstlineno, c.co_lnotab, c.co_freevars, c.co_cellvars)
    nf = new.function(nc, func.func_globals, name)
    return nf

f1 = make_named_func('onename')
print f1('fee', 'fie', 'foo', 'fum')

def raiser(): return 1/0

f2 = make_named_func('nametwo', raiser)
print f2()


This works equally well in both Python 2.2 and 2.3.  Of course, it would
be MUCH easier if co_name wasn't a *read-only* attribute of code objects
(we could just assign c.co_name in that case...), but, oh well...;-).


Alex





More information about the Python-list mailing list