Having already use flat packages, I was not expecting the issue I encountered with nested packages. Here is…
dir | +-- test.py | +-- package | +-- __init__.py | +-- subpackage | +-- __init__.py | +-- module.py
Both package/__init__.py
and package/subpackage/__init__.py
are empty.
module.py
# file `package/subpackage/module.py` attribute1 = "value 1" attribute2 = "value 2" attribute3 = "value 3" # and as many more as you want...
test.py
(3 versions)# file test.py from package.subpackage.module import * print attribute1 # OK
That's the bad and unsafe way of importing things (import all in a bulk), but it works.
# file test.py import package.subpackage.module from package.subpackage import module # Alternative from module import attribute1
A safer way to import, item by item, but it fails, Python don't want this: fails with the message: "No module named module". However …
# file test.py import package.subpackage.module from package.subpackage import module # Alternative print module # Surprise here
… says <module 'package.subpackage.module' from '...'>
. So that's a module, but that's not a module /-P 8-O ... uh
# file test.py v3 from package.subpackage.module import attribute1 print attribute1 # OK
This one works. So you are either forced to use the overkill prefix all the time or use the unsafe way as in version #1 and disallowed by Python to use the safe handy way? The better way, which is safe and avoid unecessary long prefix is the only one which Python reject? Is this because it loves import *
or because it loves overlong prefixes (which does not help to enforce this practice)?.
Sorry for the hard words, but that's two days I trying to work around this stupid‑like behavior. Unless I was totally wrong somewhere, this will leave me with a feeling something is really broken in Python's model of package and sub‑packages.
Notes
sys.path
, to avoid global side effects, nor on *.pth
files, which are just another way to play with sys.path
with the same global effets. For the solution to be clean, it has to be local only. Either Python is able to handle subpackage, either it's not, but it should not require to play with global configuration to be able to handle local stuff.package/subpackage/__init__.py
, but it solved nothing, it do the same, and complains subpackage
is not a known module, while print subpackage
says it's a module (weird behavior, again).May be I'm entirely wrong tough (the option I would prefer), but this make me feel a lot disappointed about Python.
Any other known way beside of the three I tried? Something I don't know about?
(sigh)
----- %< ----- edit ----- >% -----
There is nothing like real sub‑package in Python, as all package references goes to a global dictionnary, only, which means there's no local dictionary, which implies there's is no way to manage local package reference.
You have to either use full prefix or short prefix or alias. As in:
from package.subpackage.module import attribute1 # An repeat it again an again # But after that, you can simply: use_of (attribute1)
from package.subpackage import module # Short but then you have to do: use_of (module.attribute1) # and repeat the prefix at every use place
Or else, a variation of the above.
from package.subpackage import module as m use_of (m.attribute1) # `m` is a shorter prefix, but you could as well # define a more meaningful name after the context
If you don't mind about importing multiple entity all at once in a batch, you can:
from package.subpackage.module import attribute1, attribute2 # and etc.
Not in my first favorite taste (I prefer to have one import statement per imported entity), but may be the one I will personally favor.
Update (2012-09-14):
Finally appears to be OK in practice, except with a comment about the layout. Instead of the above, I used:
from package.subpackage.module import ( attribute1, attribute2, attribute3, ...) # and etc.
A Python package in simple words is a directory that contains Python files. Just like a directory has sub-directories and those sub-directories also have files inside, a Python package also has sub-packages and those sub-packages again have different modules defined inside.
Either Python is able to handle subpackage, either it's not, but it should not require to play with global configuration to be able to handle local stuff.
A module is a file containing Python code in run time for a user-specific code. A package also modifies the user interpreted code in such a way that it gets easily functioned in the run time. A python “module” consists of a unit namespace, with the locally extracted variables.
You seem to be misunderstanding how import
searches for modules. When you use an import statement it always searches the actual module path (and/or sys.modules
); it doesn't make use of module objects in the local namespace that exist because of previous imports. When you do:
import package.subpackage.module from package.subpackage import module from module import attribute1
The second line looks for a package called package.subpackage
and imports module
from that package. This line has no effect on the third line. The third line just looks for a module called module
and doesn't find one. It doesn't "re-use" the object called module
that you got from the line above.
In other words from someModule import ...
doesn't mean "from the module called someModule that I imported earlier..." it means "from the module named someModule that you find on sys.path...". There is no way to "incrementally" build up a module's path by importing the packages that lead to it. You always have to refer to the entire module name when importing.
It's not clear what you're trying to achieve. If you only want to import the particular object attribute1, just do from package.subpackage.module import attribute1
and be done with it. You need never worry about the long package.subpackage.module
once you've imported the name you want from it.
If you do want to have access to the module to access other names later, then you can do from package.subpackage import module
and, as you've seen you can then do module.attribute1
and so on as much as you like.
If you want both --- that is, if you want attribute1
directly accessible and you want module
accessible, just do both of the above:
from package.subpackage import module from package.subpackage.module import attribute1 attribute1 # works module.someOtherAttribute # also works
If you don't like typing package.subpackage
even twice, you can just manually create a local reference to attribute1:
from package.subpackage import module attribute1 = module.attribute1 attribute1 # works module.someOtherAttribute #also works
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