Python: importing a subpackage or submodule

Already having flat packages, I did not expect the problem that I encountered with nested packages. Here ...

Catalog layout

dir | +-- test.py | +-- package | +-- __init__.py | +-- subpackage | +-- __init__.py | +-- module.py 

Contents of init .py

Both package/__init__.py and package/subpackage/__init__.py are empty.

module.py content

 # file `package/subpackage/module.py` attribute1 = "value 1" attribute2 = "value 2" attribute3 = "value 3" # and as many more as you want... 

Contents of test.py (3 versions)

Version 1

 # file test.py from package.subpackage.module import * print attribute1 # OK 

This is a bad and unsafe way to import things (import everything in a large amount), but it works.

Version 2

 # 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 doesn't want it: crash: the message "No module named module" is missing. 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 the module, but not the module / -P 8-O ... uh

Version 3

 # file test.py v3 from package.subpackage.module import attribute1 print attribute1 # OK 

It works. So you are either forced to use the overkill prefix all the time, or use an unsafe method, like in version 1, and prevent Python from using the safe method? The best way that is safe and avoids an unnecessary long prefix is ​​the only one that rejects Python? Is it because he likes import * or because he likes too much prefixes (which doesn't help enforce this practice)?

Sorry for the hard words, but in two days I’m trying to get around this stupid behavior. If I were completely wrong somewhere, it will leave me with the feeling that something is really broken in the Python package and subpackage model.

Notes

  • I don't want to rely on sys.path to avoid global side effects or *.pth , which are another way to play with sys.path with the same global effects. For a solution to be clean, it must be only local. Either Python is able to handle the subpacket or not, but it should not require playing with the global configuration in order to be able to process local files.
  • I also tried using the import in package/subpackage/__init__.py , but he didn’t solve anything, he does the same and complains that subpackage not a known module, and print subpackage talks about this module (strange behavior, again).

I may be completely wrong (the option I would prefer), but it makes me feel very disappointed in Python.

Any other known method besides the three that I tried? Something I don't know about?

(Sigh)

-----% <----- edit ----->% -----

Conclusion so far (after user comments)

In Python, there is nothing like a real subpackage, since all package links refer only to the global dictionnary, which means that there is no local dictionary, which means that there is no way to manage the link of the local package.

You need to either use the full prefix, or a short prefix or an alias. How in:

Full prefix version

 from package.subpackage.module import attribute1 # An repeat it again an again # But after that, you can simply: use_of (attribute1) 

Short prefix version (but duplicate prefix)

 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, the option is higher.

 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 

Factored Version

If you do not mind importing several objects at the same time in batch mode, you can:

 from package.subpackage.module import attribute1, attribute2 # and etc. 

Not in my first favorite taste (I prefer to have one import statement for the imported object), but there may be one that I personally approve of.

Update (2012-09-14):

Finally, in practice, this looks fine, with the exception of comments about the layout. Instead, I used:

 from package.subpackage.module import ( attribute1, attribute2, attribute3, ...) # and etc. 
+56
python import module package
Sep 01 '12 at 16:45
source share
3 answers

You seem to misunderstand how import searches for modules. When you use the import statement, it always looks for the actual path to the module (and / or sys.modules ); it does not use module objects in the local namespace that exist due to previous imports. When you do:

 import package.subpackage.module from package.subpackage import module from module import attribute1 

The second line searches for a package called package.subpackage and imports module from this package. This line does not affect the third line. The third line simply searches for a module called module and does not find it. It does not "reuse" an object named module that you got from the line above.

In other words, from someModule import ... does not mean "from a module called someModule, which I imported earlier ...", it means "from a module called someModule, which you will find on sys.path ...". It is not possible to "step by step" create a path to a module by importing packages that lead to it. When importing, you must always refer to the entire name of the module.

It is not clear what you are trying to achieve. If you want to import a specific attribute of object1, just do from package.subpackage.module import attribute1 and do with it. You do not need to worry about the long package.subpackage.module after importing the name you want from it.

If you want to access the module to access other names later, you can do from package.subpackage import module , and as you saw, you can do module.attribute1 and so on as much as you like.

If you want both --- that is, if you want attribute1 be available directly, and you want module be available, 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 entering package.subpackage twice more, you can simply create a local link to attribute1:

 from package.subpackage import module attribute1 = module.attribute1 attribute1 # works module.someOtherAttribute #also works 
+48
Sep 01 '12 at 17:09
source share
β€” -

Reason # 2 failed due to the fact that sys.modules['module'] does not exist (the import procedure has its own scope and cannot see the local name module ), and there is no module module or package on disk. Note that you can separate multiple imported names with commas.

 from package.subpackage.module import attribute1, attribute2, attribute3 

also:

 from package.subpackage import module print module.attribute1 
+7
Sep 01 '12 at 16:50
source share

If all you are trying to do is get attribute1 in your global namespace, version 3 looks just fine. Why is this an overkill prefix?

In version 2, instead of

 from module import attribute1 

You can do

 attribute1 = module.attribute1 
0
Sep 01
source share



All Articles