Tim Johnson wrote:
* Steven D'Aprano <st...@pearwood.info> [110108 19:46]:
A more detailed response.

Dear me... messing with globals and locals. That's always a bad sign. But let's assume this is that one time in 100 that it is actually justified...

if localvals is None: self.locals = sys._getframe(1).f_locals
Are you aware that this is non-portable and subject to change without notice?
No! 1)Can you explain further?

The convention in Python is that any name that starts with a single leading underscore is a private implementation detail, and therefore subject to change. _getframe starts with a single underscore.

Of course, it's been around effectively forever -- it was introduced in Python 2.1, and is unlikely to be removed any time soon. But it *could* be, and it could happen without notice, so you have to weigh up the benefit you get from using an implementation detail against the risk of it disappearing.

On the plus side, it is a *documented* internal detail, which suggests that it won't disappear without notice.

http://docs.python.org/library/sys.html#sys._getframe

But notice that it is specific to CPython (the version you are using). Other Pythons, such as Jython, IronPython, PyPy, Stackless, and many others, may not include this function. So code using it is non-portable.

(E.g. IronPython only supports frames if you pass the commandline switch -X:Frames or -X:FullFrames.)

(Also note that PyPy is now about twice as fast as CPython. I would expect that over the next few years, PyPy should start to take off as the preferred Python implementation.)


  And you have convinced me, and furthermore given me enough to
  convince someone else that a different approach would be safer.
  2)Can you recommend a *simple* templatting module?


You haven't actually told us what you're trying to do, so I have to guess. That means I may have misunderstood something. But it looks like you want to be able to use templating of arbitrary variable names.

Perhaps your Evalx class is overkill. Maybe this is all you need:

>>> a = 42
>>> mydict = globals().copy()
>>> mydict.update(locals())
>>> "value = %(a)s" % mydict
'value = 42'

You might also like to look at the string.Template class, which is for substituting $ templates.

If you want to stick with Evalx, the approach I'd consider is:

* support globals() and locals() if they are explicitly given (*reading* is safer than *writing*);

* support automatic lookup of globals and locals only when supported, otherwise fail gracefully;

* don't use eval unless you really need to;

* if you think you need to, you probably don't :)


That means that instead of:

if localvals is None:
    self.locals = sys._getframe(1).f_locals

do something like this:

if localvals is None:
    try:
        self.locals = sys._getframe(1).f_locals
    except AttributeError:
        self.locals = {}

(and similarly for globals).


Then get rid of the eval in your __getitem__. You probably don't *really* need to support cases like this, no matter how tempting it might be:

a = 42
b = 23
"value = %(a+b)s" % Evalx()
=> "value 75"

Instead:

     def __getitem__(self, key):
        if key in self.locals: return self.locals[key]
        elif key in self.globals: return self.globals[key]
        else: return "Key? What key?"
        # Or raise KeyError



--
Steven

_______________________________________________
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor

Reply via email to