[Tutor] Dynamically naming functions

Kent Johnson kent37 at tds.net
Mon Mar 13 12:17:43 CET 2006


Ed Singleton wrote:
> On 10/03/06, Kent Johnson <kent37 at tds.net> wrote:
> 
>>Ed Singleton wrote:
>>>I want to use this in a few different places.  For example Faces, the
>>>Python Project Management Planner Tool Thingy, uses nested functions
>>>to put tasks within a project:
>>>
>>>def MyProject():
>>>    start = "2006-03-06"
>>>    resource = Me
>>>
>>>    def Task1():
>>>        start = "2006-03-13"
>>>
>>>    def Task2():
>>>        effort = "1w"
>>>
>>>I'd like to load these from a database (using SQLObject), but I'm not
>>>sure how I can define the name of the function from a filed in a
>>>database (or read in from a text file).
>>
>>This is truly bizarre use of nested functions. Faces must be looking at
>>the compiled function objects to pick this out.
> 
> 
> To be honest, this didn't seem that bizarre to me.  If I understand
> properly (which I probably don't) functions are just callable objects
> like any other callable object (or at least can be treated as such). 
> Isn't this just a handy way of creating a nested object structure
> that's readable?

Why not just use nested dicts?

MyProject = dict(
   start = "2006-03-06",
   resource = Me,
   Task1 = dict(start = "2006-03-13"),
   Task2 = dict(effort = "1w"),
)

Maybe the appearance isn't quite as nice but the intent is clear, the 
code to access the data is *much* simpler, and it lends itself to the 
kind of programmatic creation you are trying to do. Take a look at 
task.Task._compile() in the faces source to see the gyrations it takes 
to extract the data in functional form. The Zen of Python says,
   "Explicit is better than implicit"
   "Simple is better than complex"

>>In general you can set an attribute of an object using setattr():
>>   setattr(foo, 'bar', 3)
>>is the same as
>>   foo.bar = 3
>>but the attribute name is specified as a string so it can be determined
>>at runtime.
> 
> 
> This makes sense, and I think I can see how I would use it.
> 
> To create a bunch of objects from some data (just name and start date):
> 
> for fname, startdate in data:
>     def foo:
>         start = ""
>     setattr(foo, __name__, fname)
>     setattr(foo, start, startdate)
> 
> Sorting out the nesting should be fairly straightforward (if the above works).

No, it won't work. A function attribute is not the same as a local 
variable of the function. What you propose is essentially
def foo(): pass
foo.bar = 'data'

but what you need is
def foo():
   bar = 'data'

which is very different.

faces looks at foo.func_code.co_names to find the names you have used, 
and it actually runs the function with a tracing hook to capture the values.

There doesn't seem to be any other way to define a Task in faces, 
either. You have to actually create functions. I guess this might be a 
good place to use exec - just create the source code for the function 
defs in a string and exec it, then retrieve the function from the global 
namespace and pass it to faces. Then tell me why this API is better than 
using nested dicts.

Kent
Kent



More information about the Tutor mailing list