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