Python modules with identical names (i.e., reusing standard module names in packages)
Asked Answered
C

4

22

Suppose I have a package that contains modules:

SWS/
  __init.py__
  foo.py
  bar.py
  time.py

and the modules need to refer to functions contained in one another. It seems like I run into problems with my time.py module since there is a standard module that goes by the same name.

For instance, in the case that my foo.py module requires both my SWS.time and the standard python time modules, I run into trouble since the interpreter will look inside the package and find my time.py modules before it comes across the standard time module.

Is there any way around this? Is this a no-no situation and should modules names not be reused?

Any solutions and opinions on package philosophy would be useful here.

Centi answered 8/5, 2012 at 15:16 Comment(5)
I think it's pretty obvious that you should not reuse standard python module names. It's just asking for trouble.Inflame
Why is it obvious? </devilsadvocate>Vallo
Look at httplib/httplib2 and urllib/urllib2. It makes for an uglier world of libraries, but that is preferable to name collisions and indeterminate behavior.Importance
It might also be worth adding that the python style guide recommends using class_ over class (a trailing underscore) when you're trying to avoid name clashes with keywords. It might be appropriate here, and to use import time_ as time.Absolutely
Some 14 years ago I made a module called wave. Trying it out after a long time, it did not work anymore. Turned out that in the mean time a standard module by that name has been added. Yes, I know, I must be old... (and I wasn't clearvoyant). Pretty obvious: Don't judge too quickly.Cyan
C
20

Reusing names of standard functions/classes/modules/packages is never a good idea. Try to avoid it as much as possible. However there are clean workarounds to your situation.

The behaviour you see, importing your SWS.time instead of the stdlib time, is due to the semantics of import in ancient python versions (2.x). To fix it add:

from __future__ import absolute_import

at the very top of the file. This will change the semantics of import to that of python3.x, which are much more sensible. In that case the statement:

import time

Will only refer to a top-level module. So the interpreter will not consider your SWS.time module when executing that import inside the package, but it will only use the standard library one.

If a module inside your package needs to import SWS.time you have the choice of:

  • Using an explicit relative import:

    from . import time
    
  • Using an absolute import:

    import SWS.time as time
    

So, your foo.py would be something like:

from __future__ import absolute_import

import time

from . import time as SWS_time
Certainty answered 4/3, 2015 at 12:14 Comment(1)
I would argue that it is not a bad idea when the module name is in the presence of a namespace, like a package. This is the spirit of PEP328. See my answer below.Jigging
J
13

It depends on what version of Python you're using. If your targeted Python version is 2.4 or older (in 2015, I sure hope not), then yes it would be bad practice as there is no way (without hacks) to differentiate the two modules.

However, in Python 2.5+, I think that reusing standard lib module names within a package namespace is perfectly fine; in fact, that is the spirit of PEP328.

As Python's library expands, more and more existing package internal modules suddenly shadow standard library modules by accident. It's a particularly difficult problem inside packages because there's no way to specify which module is meant. To resolve the ambiguity, it is proposed that foo will always be a module or package reachable from sys.path . This is called an absolute import.

The python-dev community chose absolute imports as the default because they're the more common use case and because absolute imports can provide all the functionality of relative (intra-package) imports -- albeit at the cost of difficulty when renaming package pieces higher up in the hierarchy or when moving one package inside another.

Because this represents a change in semantics, absolute imports will be optional in Python 2.5 and 2.6 through the use of from __future__ import absolute_import

SWS.time is clearly not the same thing as time and as a reader of the code, I would expect SWS.time to not only use time, but to extend it in some way.

So, if SWS.foo needs to import SWS.time, then it should use the absolute path:

# in SWS.foo

# I would suggest renaming *within*
# modules that use SWS.time so that
# readers of your code aren't confused
# with which time module you're using
from SWS import time as sws_time

Or, it should use an explicit relative import as in Bakuriu's answer:

# in SWS.foo

from . import time as sws_time

In the case that you need to import the standard lib time module within the SWS.time module, you will first need to import the future feature (only for Python 2.5+; Python 3+ does this by default):

# inside of SWS.time
from __future__ import absolute_import

import time

time.sleep(28800)  # time for bed

Note: from __future__ import absolute_imports will only affect import statements within the module that the future feature is imported and will not affect any other module (as that would be detrimental if another module depends on relative imports).

Jigging answered 1/11, 2015 at 15:54 Comment(2)
Note that your quote from PEP 8 is obsolete. The current version of PEP 8 endorses using relative imports: quote: * explicit relative imports are an acceptable alternative to absolute imports, especially when dealing with complex package layouts where using absolute imports would be unnecessarily verbose*Certainty
@Bakuriu, well darn. I didn't know that PEPs could change like that. I will update my answer. I will still maintain my argument, however, that having a packaged module whose name is the same as a top-level stdlib module is not only permissible, but encouraged.Jigging
T
6

As others have said, this is generally a bad idea.

That being said, if you're looking for potential workarounds, or a better understanding of the problem, I suggest you read the following SO questions:

Tempo answered 8/5, 2012 at 15:24 Comment(0)
O
0

Yeah, really no good way around it. Try not to name your modules like standard packages. If you really want to call your module time, i'd recommend using _time.py instead. Even if there was a way to do it, it would make your code hard to read and confusing when it came to the 2 time modules.

Oxygenate answered 8/5, 2012 at 15:19 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.