views:

245

answers:

1

I have a Python package mymodule with a sub-package utils (i.e. a subdirectory which contains modules each with a function). The functions have the same name as the file/module in which they live.

I would like to be able to access the functions as follows,

from mymodule.utils import a_function

Strangely however, sometimes I can import functions using the above notation, however other times I cannot. I have not been able to work out why though (recently, for example, I renamed a function and the file it was in and reflected this rename in the utils.__init__.py file but it no longer imported as a functions (rather as a module) in one of my scripts.

The utils.__init__.py reads something like,

__all__ = ['a_function', 'b_function' ...]
from a_function import a_function
from b_function import b_function
...

mymodule.__init__.py has no reference to utils

Ideas?

+3  A: 

Do your utils functions need to import other utils functions? (or import other modules that import other utils functions). Suppose for example that a_function.py contains contains "from mymodule.utils import b_function". Here's your utils.py with a bunch of extra comments:

# interpreter is executing utils.py
# Right now, utils.a_function and utils.b_function are modules

# The following line executes the a_function module, 
# then rebinds a_function to a_function.a_function
from a_function import a_function 

# The following line executes the b_function module, 
# then rebinds b_function to b_function.b_function
from b_function import b_function

When the a_function module is first imported by utils.py, utils.b_function is a module not a function. Any module that states "from mymodule.utils import b_function" before the last line is executed will end up with a reference to the b_function module instead of the b_function function.

In general, I find that the from somemodule import something idiom is fraught with peril for any large project. It's great for short scripts, but once you start introducing circular import dependencies you run into problems and need to be careful about where you use it.

As a compromise between safety and saving on typing, I'd use from mymodule import utils then call utils.a_function(). That way, you will always get the object bound to utils.a_function right now instead of whatever happened to be bound to utils.a_function during import.

Daniel Stutzbach
So what's the difference between `import mymodule.utils as utils` and `from mymodule import utils`?
Mike DeSimone
@Mike DeSimone: Good point. I updated my answer accordingly.
Daniel Stutzbach