String changing on the fly

Alex Martelli aleaxit at yahoo.com
Thu Oct 21 10:34:58 CEST 2004


Eli Daniel <elie at flashmail.com> wrote:
   ...
> > As others have said, you need to pass do_action the dictionary of the
> > local variables of the function (or module's body) from which you're
> > calling it: do_action('it cost $T dollars', vars()).  If you don't pass
> > this argument explicitly it IS possible for do_action to recover it by
> > black magic, but that would be very bad practice.
> > 
> > Apart from this, your best bet might be to upgrade to 2.4 (the current
> > beta appears quite good), which offers exactly this functionality in the
> > string.Template class.  Otherwise, see how string.py does it (in the 2.4
> > standard library) and copy the solution.  But reusing the solution
> > directly is much preferable, and for that you need 2.4.
   ...
> Thank you all.

You're welcome.

> I've written a solution which sends that vars on every function call
> as suggested (do_action('it cost $T dollars', vars()) which works
> great.

Good!

> I've spent some time trying to avoid sending the vars (before I saw
> the previous post) with no much success (I've tried all kind of
> imports which resulted in some weird issues for a new guy like me).
> I'll try the beta, if it solves the problem that's great and if not
> the above solution is good as well.

It doesn't, per se, allow you to avoid passing vars() -- it just supples
in class string.Template the functionality for $-interpolation.

To avoid passing vars() you need black magic inside function do_action:
it must root around in the call-stack and find out the local variables
of its caller.  That's not impossible, but it's not considered Python
style.  "Explicit is better than implicit": when you pass vars() it's
obvious that the function is going to use the value of some of your
local variables, and you also gain some flexibility by being able to
pass another dictionary; when you pass nothing, it's pretty deep and
dark and mysterious what IS going to happen.

If you feel you must allow calling do_action without vars(), while not
recommended and not good Python style, you can.  Python shares 4.5 out
of 5 principles that define the Spirit of C according to the intro of
C's official standard, after all, and the first two are:
1. trust the programmer
2. don't prevent the programmer from doing what needs to be done.

so, here's the 2.4 code one might use for that (NOT recommended...):

import string, inspect

def do_action(message, thevars=None)
    if thevars is None:
        thevars = inspect.currentframe(1).f_locals
    print string.Template(message) % thevars


The black magic is the call to inspect.currentframe, which is very
clearly documented (at an interactive prompt, do import inspect and then
help(inspect.currentframe)) with:
'''
This function should be used for internal and specialized purposes only.
'''

Well, maybe not THAT clear, but hopefully scary enough.  The concept is:
if you know what you're doing, we trust you, and we don't prevent you
from doing what you judge NEEDS to be done, even though it requires
black magic that reaches behind the scenes of the execution model,
plucking a frame out of the call-stack and accessing its implementation
detail 'f_locals' attribute -- "on your head be it";-).

Just be sure it NEEDS to be done -- be sure it's a PROBLEM to do things
cleanly, explicitly, simply, and in the obvious way -- Python strongly
urges you to rethink your framing of the issue, but doesn't force you.


Alex



More information about the Python-list mailing list