Getting in to metaprogramming
Steven D'Aprano
steve at REMOVE-THIS-cybersource.com.au
Thu Nov 27 21:21:59 EST 2008
On Fri, 28 Nov 2008 05:05:10 +0200, Hendrik van Rooyen wrote:
> "Terry Reedy" <tjreedy at udel.edu> wrote:
>
>
>> Hendrik van Rooyen wrote:
>>
>> > I am using the term in the restricted sense of Python writing Python
>> > source.
>> >
>> > Given that, can anybody think of an example that you could not do
>> > with a class? (excepting the "stored procedure" aspect)
>>
>> I am not sure I understand your question.
>>
>> def iterize(recursive_function_text):
>> <code to parse input and fill a template> return
>> equivalent_iterative_function_text
>>
>> where input and output are both Python code. If one were to implement
>> this by compiling the input to AST form and then walking the tree, the
>> AST node classes would be involved, but I would scarely say the
>> translation was done by the classes, as opposed to functions which
>> might or might not be attacked to a class as methods.
>>
>>
> I am not sure I understand the answer - if the input and output are both
> bits of python source, then the output must be stored and evaluated or
> imported to get it executed, right?
I think there's some confusion here. Python, like all general-purpose
programming languages, is able to process text. Python source code, like
that of almost all programming languages, is text.
Therefore Python can process Python source code as text: it can read it
and process it, or it can write it. There's nothing mysterious about
this, although how useful it is depends on the nature of the processing.
Once you have that Python source code, it is no different whether you
wrote it by hand, or wrote it with the aid of another program. To execute
it, you have to execute it.
Here's a trivial example of metaprogramming. Suppose I am interested in
the compilation time of Python code, rather than the execution time. I
might do this:
numitems = 100000
template = """def main():
# %s
%s%s
return L
"""
def make_file(name, comment, setup, body):
f = open(name, 'w')
f.write(template % (comment, setup, body))
f.close()
body = 'L.append(None)\n'
make_file('dumb.py', 'Create a big list the dumb way.',
'L = []\n', body*numitems)
make_file('smart.py', 'Create a big list the smart way.',
'', 'L = [None]*%d\n' % numitems)
At this point, I have two source files which I can do anything I like
with. It would have been a real pain to have written the first one by
hand, even with a clever editor. I can post-process them, run them
through other tools, even open them up in an editor and manipulate them
by hand (although that defeats the purpose of metaprogramming). Now I can
run the source files as input to another piece of code, and get a (very
rough) estimate of the compilation time:
from time import time
start = time()
execfile('dumb.py') # bypass the import mechanism
tdumb = time() - start
print "Time taken to compile dumb.py is %f seconds" % tdumb
start = time()
execfile('smart.py')
tsmart = time() - start
print "Time taken to compile smart.py is %f seconds" % tsmart
On my computer, I get:
Time taken to compile dumb.py is 2.236122 seconds
Time taken to compile smart.py is 0.003754 seconds
--
Steven
More information about the Python-list
mailing list