Emulating !ActionScript's "with" statement in Python
If you haven't had much to do with ActionScript or Visual Basic, right now you might be thinking, as I did, "huh?" Basically the with statement in both of these languages allows one to access the attributes of an object as if they were in the local scope.
I know, I know. Why would you want to do this? I have no idea, but I thought it was cool that it was even possible in Python. However, there are some fairly major limitations:
- It only works in a global scope (I neglected to mention this originally, apologies - see #74 for details). One can s/f_locals/f_globals/g but this introduces its own problems.
- It only works for objects with a mutable __dict__.
I also thought the approach of injecting symbols into the context could be useful for providing DSL-like features. eg.
with query('a', 'b', 'c') as result: SELECT(a.foo, b.bar, c.baz) WHERE(AND(a.foo == 10, b.bar == 20)) ORDER_BY(a.foo) GROUP_BY(b.bar) for row in result: print row.foo, row.bar, row.baz
etc.
But enough speculation, here is an actual example. It requires at least Python 2.5.
And finally, here's the actual code.
from __future__ import with_statement import inspect class scope(object): """A context that maps an objects attributes into the current lexical scope, only for the duration of the context. NB. Properties will NOT work. >>> import math >>> with scope(math): ... print sqrt(9) 3.0 >>> class Vector: ... def __init__(self, x, y): ... self.x = x ... self.y = y ... def length(self): ... return math.sqrt(self.x ** 2 + self.y ** 2) >>> v = Vector(3, 3) >>> with scope(v): ... print x, '%0.2f' % length() ... x = 4 ... print x, '%0.2f' % length() 3 4.24 4 5.00 >>> print v.x, v.y, v.length() 4 3 5.0 >>> print x Traceback (most recent call last): ... NameError: name 'x' is not defined """ def __init__(self, obj): self.members = dict(inspect.getmembers(obj)) self.obj = obj def __enter__(self): parent = inspect.currentframe().f_back # Preserve parent locals() and the objects dictionaries self.old_locals = dict(parent.f_locals) self.old_dict = self.obj.__dict__ # Update locals with object members parent.f_locals.update(self.members) # If possible, replace the object's __dict__ with our updated locals. # Functions on the object that operate on the attributes will then # continue to work as expected. The downside is that all other objects # in the parents scope will be included as well. try: self.obj.__dict__ = parent.f_locals self.fake_dict = True except (TypeError, AttributeError): self.fake_dict = False def __exit__(self, type, value, traceback): parent = inspect.currentframe().f_back if self.fake_dict: object_dict = self.old_dict else: object_dict = self.obj.__dict__ # Replicate member state from locals to object's __dict__. for key in self.members: if key in parent.f_locals: object_dict[key] = parent.f_locals[key] if key not in self.old_locals: del parent.f_locals[key] else: del object_dict[key] if self.fake_dict: self.obj.__dict__ = object_dict del self.old_locals del self.old_dict return False if __name__ == '__main__': import doctest doctest.testmod()

rss
Comments
Nice ! :).. Thanks buddy..