I am trying to dynamically import a configuration file in Python.
My code works fine when I use:
import conf.config as config
but doesn't work correctly when I use:
config = __import__("conf.config")
Below are to sample programs and the results I get when running them:
#regularimport.py
import conf.config as config
def read_values(cfg):
for varname in cfg.__dict__.keys():
if varname.startswith('__'):
continue
value = getattr(cfg, varname)
yield (varname, value)
for name,value in read_values(config):
print "Current config: %s = %s" % (name, value)
Results:
$python regularimport.py
Current config: SETTING_TWO = another setting
Current config: SETTING_ONE = some setting
Dynamic import:
#dynamicimport.py
conf_str = "conf.config"
config = __import__(conf_str)
def read_values(cfg):
for varname in cfg.__dict__.keys():
if varname.startswith('__'):
continue
value = getattr(cfg, varname)
yield (varname, value)
for name,value in read_values(config):
print "Current config: %s = %s" % (name, value)
Results:
$ python dynamicimport.py
Current config: config = <module 'conf.config' from '/home/ubuntu/importex/conf/config.pyc'>
My question is why the difference? And more importantly, how can I make the dynamic import example work as it does with the regular import?
As the documentation explains:
When the name variable is of the form
package.module
, normally, the top-level package (the name up till the first dot) is returned, not the module named by name.
So, when you do this:
config = __import__("conf.config")
That's not the same as:
import conf.config as config
But rather something more like:
import conf.config
config = conf
Why?
Because conf
, not conf.config
, is the thing that gets bound by an import
statement. (Sure, in import foo as bar
, obviously bar
gets bound… but __import__
isn't meant to be an equivalent of import foo as bar
, but of import foo
.) The docs explain further. But the upshot is that you probably shouldn't be using __import__
in the first place.
At the very top of the function documentation it says:
Note: This is an advanced function that is not needed in everyday Python programming, unlike
importlib.import_module()
.
And at the bottom, after explaining how __import__
works with packages and why it works that way, it says:
If you simply want to import a module (potentially within a package) by name, use
importlib.import_module()
.
So, as you might guess, the simple solution is to use importlib.import_module
.
If you have to use Python 2.6, where importlib
doesn't exist… well, there just is no easy solution. You can build something like import_module
yourself out of imp
. Or use __import__
and then dig through sys.modules
. Or __import__
each piece and then getattr
your way through the results. Or in various other hacky ways. And yes, that sucks—which is why 3.0 and 2.7 fixed it.
The 2.6 docs give an example of the second hack. Adapting it to your case:
__import__("conf.config")
config = sys.modules["conf.config"]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With