[Tutor] Dynamically naming functions

Ed Singleton singletoned at gmail.com
Mon Mar 13 14:49:23 CET 2006


On 13/03/06, Kent Johnson <kent37 at tds.net> wrote:
> 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"

Point taken.  Dict's are easier.  And the appearance is fine.

I've just discovered with a little playing, that you can do:

>>> def z(v):
...     def f(x):
...             print x * v
...     return f
...
>>> c = z(3)
>>> c(1)
3
>>> funcdict = dict(foo = z(4))
>>> funcdict["foo"](1)
4

Which was obvious enough that I thought of trying it, but surprising
enough that I was really pleased when it worked.

> >>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.

Agreed, though to be fair the author of faces has probably
overcomplicated the code for handling it (which is a damn shame as it
is really quite a nice project planning tool).  I guess you can't
blindly iterate over the methods of functions, as there are other
methods there that you might not want to use (like setattr and stuff,
maybe?).

Ed


More information about the Tutor mailing list