Victor Subervi wrote:
On Sun, Nov 29, 2009 at 10:23 PM, Dave Angel <da...@ieee.org> wrote:
exec is a statement, and statements don't have "return values." It's not
a function, so there are no parentheses in its syntax, either. exec is also
a technique of last resort; there's nearly always a better/safer/faster way
to accomplish what you might want, but of course you don't say what that is.
As for "returning" values, exec by default uses the same global space as
your app, so you can just modify a global variable in your "called" code and
use it afterwards.
abc = 42
value = 12
exec "abc = %d" % value
print abc
Taking out the parenthesis did it! Thanks. Now, you state this is an option
of last resort. Although this does indeed achieve my desired aim, here is a
complete example of what I am trying to achieve. The following is from
'createTables2.py':
for table in tables:
try:
exec 'from options import %s' % table
except:
pass
try:
exec '%s()' % table
except:
pass
The following is from 'options.py':
def jewelry(which=''):
code = []
names = []
meanings = []
code.append(['5', '5½', '6', '6½', '7', '7½', '8',
'8½', '9', '9½', '10', '10½', '11', '11½', '12',
'12½', '13', '13½'])
meanings.append('The standard ring sizes.')
names.append('ringSizes')
code.append(['Petite (7")', 'Average (7½")', 'Large
(8")', 'Extra-large (8½")'])
meanings.append('The standard bracelet sizes.')
names.append('braceletSizes')
code.append(['16"', '18"', '20"', '22"', '24"'])
meanings.append('The standard necklace sizes.')
names.append('necklaceSizes')
code.append(['14K gold', '18K gold', 'silver', '14K white gold', '18K
white gold', 'platinum', 'tungsten', 'titanium'])
meanings.append('The standard jewelry metals.')
names.append('metals')
code.append(['diamond', 'emerald', 'ruby', 'sapphire', 'pearl', 'opal',
'topaz', 'onyx', 'lapiz lazuli', 'tanzanite', 'garnet', 'quartz', 'rose
quartz', 'amethyst', 'alexandrite', 'peridot', 'tourmaline', 'citrine',
'turquoise'])
meanings.append('The standard jewelry stones.')
names.append('stones')
if which == '':
i = 0
all = ''
while i < len(meanings):
table = '%s\n' % meanings[i]
table += "<table>\n <tr>\n <td colspan='8' align='center'>%s</td>\n
</tr>" % names[i]
j = 0
for elt in code:
if (j + 8) % 8 == 0:
table += ' <tr>\n'
table += ' <td>%s</td>\n' % code[i]
if (j + 8) % 8 == 0:
table += ' </tr>\n'
j += 1
if table[-6:] != '</tr>\n':
table += ' </tr>\n'
table += '</table>\n'
all += table + '<br /><br />'
i += 1
print all
This all works fine; however, if there is a better way of doing it, please
let me know.
Thanks,
V
The parentheses can't do any harm for that particular expression, so
that wasn't your problem. But I'm glad you fixed whatever else was your
problem. I mentioned it because sometimes they can cause problems, and
you shouldn't get in bad habits. (things like if, return, and exec are
all statements that take an expression, but do not need parentheses.)
I'll throw in a comment here about a bare except. Also a bad idea. You
could easily mask some other problem involved in the import, and the
program silently continues. If you know of a specific problem, or
category of problems that you want to ignore, then pick an exception, or
tuple of exceptions, to do that.
The immediate question is how to get rid of exec. You're using it two
places. First case, you're just using it to extract specific objects
from that module's namespace.
Assuming you've already imported options earlier in the code, you can
replace
from options import xyzzy
by
optfunc = options.xyzzy
or
option_func = getattr(options, "xyzzy", None)
or even
option_func = getattr(options, "xyzzy", dummyfunc)
(where dummyfunc() is a function which takes no arguments and does nothing)
Now, assuming you plan to call each such function immediately, you can
just say
option_func()
in the same loop.
def dummyfunc():
pass
....
for table in tables:
option_func = getattr(options, table, dummyfunc)
option_func()
If you didn't have the dummyfunc, you'd need an "if option_func" in there.
Naturally, if this "tables" comes from the user, you need to give him
some feedback, so perhaps dummyfunc isn't an empty function after all,
but is supplied in options.py
Other comments about your code: Someone else has mentioned names, so I
won't dwell on that.
if table[-6:] != '</tr>\n':
should use endswith(), and you won't run the risk of counting wrong if
your literal changes.
if (j + 8) % 8 == 0:
could be simpler:
if j % 8 == 0:
The pattern:
j=0
for elt in code:
should be replaced by:
for j, elt in enumerate(code):
(and of course don't forget to then remove the j+=1 )
You're using the indexing variable i when it'd make much more sense to
use zip. Or perhaps meanings and code should be a single list, with
each item being a tuple. That's what zip builds, after the fact. But
if you build it explicitly, you're less likely to accidentally have an
extra or missing element in one of them, and have to deal with that bug.
The zip approach might look something like:
for meaning, code_element in zip(meanings, code):
and then whenever you're using meanings[i] you use meaning, and
whenever you're using code[i], you use code_element. (Obviously name
changes would help, since code is a list, but the name isn't plural)
More generally, when I see code with that much data embedded in it, it
cries out for templates. They're known by many different names, but the
idea is to write your data structures somewhere else, and manipulate
them with the code, instead of embedding it all together. I suspect
that each of these functions looks very similar, and they each have
their own set of bugs and glitches. That's a good indicator that you
need to separate the data.
For my web work, I've written my own, very simple templating logic
that's only as good as I needed. So I can't comment on the various ones
that are already available. But the idea is you put data into one or
more text files, which you systematically manipulate to produce your end
result. A particular text file might be comma delimited, or defined in
sections like an .ini file, or both, or some other mechanism, such as
xml. But make it easy to parse, so you can concentrate on getting the
data into its final form, consistently, and with common code for all
your tables, parameterized by the stuff in the data files.
DaveA
--
http://mail.python.org/mailman/listinfo/python-list