[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