Do eval() and exec not accept a function definition? (like 'def foo: pass) ?

vasudevram vasudevram at gmail.com
Sat Jun 23 15:58:32 EDT 2007


Hi group,

Question: Do eval() and exec not accept a function definition? (like
'def foo: pass) ?

I wrote a function to generate other functions using something like
eval("def foo: ....")
but it gave a syntax error ("Invalid syntax") with caret pointing to
the 'd' of the def keyword.

Details (sorry for the slight long post but thought it better to give
more details in this case - wording is pretty clear, though, I think,
so shouldn't take long to read):

While working on a personal project for creating a server for a
certain protocol (which I may make into an open source project later
if it turns out to be any good), I wrote some simple functions to
generate HTML start and end tags like <html>, <body>, </html>, </
body>, etc. - just to simplify/shorten my code a little. (I'm aware
that there are HTML generation libraries out there, but don't think I
need the overhead, since my needs are very simple, and anyway wanted
to roll my own just for fun. For a bigger/more serious project I would
probably use the existing libraries after doing a proper evaluation).
So, this question is not about HTML generation but about Python's
eval() function and exec statement.

Started by writing functions like this:

def start_html():
    return '<html>\r\n'

def end_html():
    return '</html>\r\n'

... and similarly for the 'body', 'p', etc. HTML tags.
(I used '\r\n' at the end because the server will send this output to
the browser over HTTP, so that my code conforms to Internet protocols,
and also so that while debugging, my output would have only one tag
per line, for readability. Not showing the '\r\n in the rest of the
code below)

Then I realized that all these functions are very similar - only
differ in the return value of the tag.
So (being interested in metaprogramming of late), thought of writing a
function that would generate these functions, when passed the
appropriate tag name argument.

[ Digression: I could of course have used another simple approach such
as this:

def start_tag(tag_name):
    return '<' + tag_name + '>'

# called like this:
# print start_tag('html')
# print start_tag('body')

# and

def end_tag(tag_name):
    return '</' + tag_name + '>'

# called like this:
# print end_tag('body')
# print end_tag('html')

# and called similarly for the other HTML tags.

While the above would work, it still would involve a bit more typing
than I'd like to do, since I'[d have to pass in the tag name as an
argument each time. I'd prefer having functions that I could call like
this:

print start_html()
# which would print "<html>"
print start_body()
# which would print "<body>"

# and so on ... just to make the code a little shorter and more
readable.

End of Digression]

So, I wrote this code generation function:

# AAAA
import string
def generate_html_tag_function(tag_name, start_or_end):
    start_or_end.lower()
    assert(start_or_end in ('start', 'end'))
    if start_or_end == 'start':
        func_def = "def start_" + tag_name + ":()\n" + \
            "return '<' + tag_name + '>'
    else:
        func_def = "def end_" + tag_name + ":()\n" + \
            "return '</' + tag_name + '>'
    function = eval(func_def)
    return function

# meant to be called like this:

start_html = generate_html_tag_function('html', 'start')
start_body = generate_html_tag_function('body', 'start')
end_html = generate_html_tag_function('html', 'end')
end_body = generate_html_tag_function('body', 'end')

# and the generated functions would be called like this:

print start_html()
print start_body()
print end_body()
print end_html()
# BBBB

# giving the output:
<html>
<body>
</body>
</html>

But when I ran the above code (between the lines marked #AAAA and
#BBBB), I got an error "Invalid syntax" with the caret pointing at the
"d" of the def statement.
I had used eval a few times earlier for somewhat similar uses, so
thought this would work.
I then looked up the Python Language Reference help, and saw that eval
is used to evaluate Python expressions, not statements, and def is a
statement. So looked up the exec statement of Python and saw that its
syntax seemed to allow what I wanted.
So replaced the line containing eval in the above with:
    exec(func_def)
But that too gave the same error (I think so - I tried this yesterday
and forgot to save the error messages, sorry about that, so can't be
sure, but do think this was the case - if not, I'll save the exact
code and output/errors later and repost here - not at my PC right
now.)

Thanks for any suggestions,

Vasudev Ram
Bize site: http://www.dancingbison.com
PDF creation / conversion toolkit: http://sourceforge.net/projects/xtopdf
Blog on software innovation: http://jugad.livejournal.com




More information about the Python-list mailing list