471,355 Members | 1,618 Online
Bytes | Software Development & Data Engineering Community
Post +

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 471,355 software developers and data experts.

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


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

Jun 23 '07 #1
6 3506
MC
Hi!

Try with change all '\r\n' by '\n'

--
@-salutations

Michel Claveau
Jun 23 '07 #2
Hey,

I think you could use lambda functions for that matter (Ever heard of
them?). You could write something like:

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':
function = lambda: '<' + tag_name + '>'
else:
function = lambda: '</' + tag_name + '>'
return function

Then you would create the functions using the same code you had
written before:

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')
That seems to do what you want.

Eduardo

Jun 23 '07 #3
On Jun 24, 1:20 am, Eduardo Dobay <edudo...@gmail.comwrote:
Hey,

I think you could use lambda functions for that matter (Ever heard of
them?). You could write something like:

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':
function = lambda: '<' + tag_name + '>'
else:
function = lambda: '</' + tag_name + '>'
return function

Then you would create the functions using the same code you had
written before:

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')

That seems to do what you want.

Eduardo
Thanks to all the repliers.

@Eduardo: Yep, I had heard of lambdas, but didn't think to use them
here.
Will try this out - thanks!

- Vasudev
Jun 23 '07 #4
vasudevram wrote:
Hi group,

Question: Do eval() and exec not accept a function definition? (like
'def foo: pass) ?
def is the first keyword in a _statement_, not an expression.

exec executes statements, eval evaluates expressions.

try this:

exec "def foolish(x):\n y= x * 2\n print x, y"
foolish(2.4)
--
--Scott David Daniels
sc***********@acm.org
Jun 23 '07 #5
On Sat, 23 Jun 2007 19:58:32 +0000, vasudevram wrote:
>
Hi group,

Question: Do eval() and exec not accept a function definition? (like
'def foo: pass) ?
eval() is a function, and it only evaluates EXPRESSIONS, not code blocks.

eval("2+3") # works
eval("x - 4") # works, if x exists
eval("print x") # doesn't work

exec is a statement, and it executes entire code blocks, including
function definitions, but don't use it. Seriously.

ESPECIALLY don't use it if you are exec'ing data collected from untrusted
users, e.g. from a web form.

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.
You don't need eval or exec to write a function that generates other
functions. What you need is the factory-function design pattern:
def factory(arg):
def func(x):
return x + arg
return func

And here it is in action:
>>plus_one = factory(1)
plus_two = factory(2)
plus_one(5)
6
>>plus_two(5)
7

--
Steven.

Jun 24 '07 #6
On Jun 24, 6:28 am, Jean-Paul Calderone <exar...@divmod.comwrote:
On Sun, 24 Jun 2007 11:17:40 +1000, Steven D'Aprano <s...@remove.this.cybersource.com.auwrote:
On Sat, 23 Jun 2007 19:58:32 +0000, vasudevram wrote:
Hi group,
Question: Do eval() and exec not accept a function definition? (like
'def foo: pass) ?
eval() is a function, and it only evaluates EXPRESSIONS, not code blocks.

Actually, that's not exactly true:
>>x = compile('def foo():\n\tprint "hi"\n', '<stdin>', 'exec')
>>l = {}
>>eval(x, l)
>>l['foo']()
hi
>>>

Jean-Paul
Thanks, all. Will check out the replies given.
- Vasudev

Jun 24 '07 #7

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

4 posts views Thread by Jean-Sébastien Bolduc | last post: by
1 post views Thread by Art | last post: by
1 post views Thread by Andr? Roberge | last post: by
10 posts views Thread by Julian Smith | last post: by
10 posts views Thread by Antoon Pardon | last post: by
6 posts views Thread by dave.g1234 | last post: by
2 posts views Thread by Danny Shevitz | last post: by

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.