44

I would like to define globals in a "programmatic" way. Something similar to what I want to do would be:

definitions = {'a': 1, 'b': 2, 'c': 123.4}
for definition in definitions.items():
    exec("%s = %r" % definition)  # a = 1, etc.

Specifically, I want to create a module fundamentalconstants that contains variables that can be accessed as fundamentalconstants.electron_mass, etc., where all values are obtained through parsing a file (hence the need to do the assignments in a "programmatic" way).

Now, the exec solution above would work. But I am a little bit uneasy with it, because I'm afraid that exec is not the cleanest way to achieve the goal of setting module globals.

0

3 Answers 3

72

Here is a better way to do it:

import sys
definitions = {'a': 1, 'b': 2, 'c': 123.4}
module = sys.modules[__name__]
for name, value in definitions.iteritems():
    setattr(module, name, value)
Sign up to request clarification or add additional context in comments.

6 Comments

Maybe you could describe why this is better?
@tom10, there's no documented guarantee that changes to globals() will actually persist the changes to the underlying module. It works today, might break tomorrow. Nadia's solution OTOH is solid (hence +1 from me;-).
I like this way of doing it, but about locals() and globals(): the current docs seem to imply it will always work: locals: Update and return a dictionary representing the current local symbol table. Warning: The contents of this dictionary should not be modified; changes may not affect the values of local variables used by the interpreter. globals: Return a dictionary representing the current global symbol table. This is always the dictionary of the current module. Maybe the docs need to be tweaked up...
Ah ah! sys.modules[…] is the key… Thank you for pointing it out! Time to study the documentation of sys
@Alex: It appears that globals() is (at least as of now) updatable. Ref.: stackoverflow.com/questions/4859217/… (discussion with ncoghlan).
|
53

You can set globals in the dictionary returned by globals():

definitions = {'a': 1, 'b': 2, 'c': 123.4}
for name, value in definitions.items():
    globals()[name] = value

4 Comments

+1, as globals() can indeed be modified (stackoverflow.com/questions/4859217/…).
Another good point brought up is that changes to globals() will persist without error, but there is no such guarantee with locals().
this causes a TypeError: '<' not supported between instances of 'int' and 'str' for me when I then call dir()
Here's Nick Coghlan's comment that clinches it for me in support of globals()[name] = value: "...given the hoops we jump through as core devs to make sure that modifying module state via globals() doesn't break... There's also plenty of standard library code that uses globals() that way."
4

You're right, exec is usually a bad idea and it certainly isn't needed in this case.

Ned's answer is fine. Another possible way to do it if you're a module is to import yourself:

fundamentalconstants.py:

import fundamentalconstants

fundamentalconstants.life_meaning= 42

for line in open('constants.dat'):
    name, _, value= line.partition(':')
    setattr(fundamentalconstants, name, value)

2 Comments

I prefer Nadia's import[__name__] to hardcoding this module's name.
Interesting: I had not thought of that! It's true that it is not robust against changing the module file name, but it's still an interesting idea that I prefer to my exec!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.