I have only a few coding tricks to pass on:
1) Instances of
self.exec_code = compile(self.exec_string,'<string>','exec')
are probably better as
self.exec_code = compile(self.exec_string,`self`,'exec')
That way tracebacks from errors during compilation will identify the
specific exec_code object that's in error.
2)
> def p(self) :
> print str(self)
'print' automatically invokes your __str__ method, so the body can be
replaced by a plain
print self
And note that, for the same reason, if x is an exec_code object,
the user gets the same output whether they do
x.p()
or
print x
This makes the .p() method marginal.
3)
> for x in range(0,self.indent_level):
> self.exec_string = self.exec_string + ' '
> self.exec_string = self.exec_string + stmt + '\n'
A) When you want a 'for' loop to execute N times, the one-argument
form of 'range' does the trick. So
for x in range(self.indent_level):
is more idiomatic here.
B) An amazing number of Python programmers don't seem to know (or
remember <grin>) that "string * int" returns string+string+...
(int catenations of "string"). So the whole sequence above can
be done in one statement:
self.exec_string = self.exec_string + ' '*self.indent_level + \
stmt + '\n'
> I would appreciate ... comments ... especially with regard to the
> namespace issues I discussed in the comments for ... execute()
The trick to this is to stare at the table in section 4.1 of the language
(not library) reference manual, until after a week or two it dawns on you
that it means exactly (& in particular, no more than) what it says <wink>.
The other trick is to realize that the rules _imply_ that, in almost all
cases (and in all non-devious cases), the global namespace used by a
chunk of code is the namespace of the module in which that code appears.
This is a good rule, because it prevents modules from stepping on each
other by accident.
So, e.g., suppose we put your module in the file eco.py. Then:
>>> import eco
>>> e = eco.exec_code()
>>> e.append_stmt('global i')
>>> e.append_stmt('i = 45')
>>> print e
<exec_code instance> with indent-level 0 and code:
--------------------------------------------------------------
global i
i = 45
>>> i = 0 # stick "i" in __main__'s global NS
>>> dir() # yup, it's there
['__name__', 'e', 'eco', 'i']
>>> dir(eco) # but "i" is not in eco's global NS
['__name__', 'exec_code']
>>> e.execute()
>>> i # *our* value of i didn't change
0
>>> dir(eco) # but eco suddenly grew one
['__name__', 'exec_code', 'i']
>>> eco.i
45
>>>
Clearer? It might help to point out that, in your
exec self.exec_code
exec's caller is the 'execute' method, not whoever _called_ execute. So
"global n.s. of caller" in table 4.1 refers here to the global NS of
function 'execute', and the global NS of a function is the global NS of
the block _containing_ the function (not of the function's caller).
That's the chain you trace thru in 4.1: it leads from the exec, to
execute, to the class defn, and ends at the module containing the class.
5.5-on-the-technical-and-5.9-for-artistic-impression-ly y'rs - tim,
the tonya harding of python
Tim Peters tim@ksr.com
not speaking for Kendall Square Research Corp