python - Rules for when recursive package imports fail -


this came in context of answering another question today.

assume following files, comments denote filenames:

# level1/__init__.py     import level1.level2     answer = level1.level2.answer  # level1/level2/__init__.py     .b import answer  # level1/level2/b.py     .a import answer     ..level2.a import answer     level1.level2.a import answer     import level1.level2.a      if answer != 42:         answer = level1.level2.a.answer  # <-- fails here  #level1/level2/a.py     answer = 42 

with code, python -c "import level1" works fine (in both 2.7 , 3.4) as-is. change answer besides 42, , fails attributeerror: 'module' object has no attribute 'level2' @ designated location.

it appears from/import can import sub-module of package , pull variables out of namespace before parent namespaces set up, (obviously) parent namespaces must set before attributes of sub-namespaces can traversed via normal attribute accesses.

sometimes, though, namespace set "well enough" import work. example, code below, top level stripped off, works python -c "import level2", though still haven't finished initializing level2 namespace when import level2.a level2.b.

# level2/__init__.py     .b import answer  # level2/b.py     .a import answer     import level2.a      if answer != 42:         answer = level2.a.answer  # <-- works here  #level1/level2/a.py     answer = 41 

edit

it appears import x.y.z insert reference z y, not insert reference y x. example, when change level1/level2/b.py first example:

# level1/level2/b.py     sys import modules      def dump():         print '\n dumping...'         key, value in sorted(modules.items()):             if key.startswith('level'):                 print key, [ x x in dir(value) if not x.startswith('_')]      dump()     import level1.level2.a     dump()      .a import answer     ..level2.a import answer     level1.level2.a import answer      if answer != 42:         answer = level1.level2.a.answer 

i following results before traceback:

 dumping... level1 [] level1.level2 [] level1.level2.b ['dump', 'modules'] level1.level2.sys []   dumping... level1 [] level1.level2 ['a'] level1.level2.a ['answer'] level1.level2.b ['dump', 'level1', 'modules'] level1.level2.level1 [] level1.level2.sys [] 

however, if, right after second call dump(), add line:

setattr(modules['level1'], 'level2', modules['level1.level2']) 

then not fail, because have bound level2 level1 before accessing via attribute lookup. however, seems if interpreter can bind a level1 on import, might able binding of level2 level in same fashion.

is there reason why lowest-level package updated during import statement, or bug (or perhaps, rather, feature added single package should extended nested packages)?

note according python documentation, when submodule loaded using any mechanism ... binding placed in parent module’s namespace submodule object..

i believe happens. not enough in cases. also, documentation may relatively new.

i have filed an issue against python. text of issue reproduced below:

pep 8 recommends absolute imports on relative imports, , section 5.4.2 of import documentation says import cause binding placed in imported module's parent's namespace.

however, since (with current python versions) binding not made until after module body has been executed, there cases relative imports work fine absolute imports fail. consider simple case of these 5 files:

xyz.py: import x x/__init__.py:  import x.y x/y/__init__.py:  import x.y.a x/y/a/__init__.py:  import x.y.b; foo = x.y.b.foo x/y/b/__init__.py:  foo = 1 

this fail in fashion may surprising uninitiated. not fail on of import statements; rather fail attributeerror on assignment statement in x.y.a, because import of y has not yet finished, y has not yet been bound x.

this conceivably fixed in import machinery performing binding before performing exec. whether can done cleanly, not cause compatibility issues existing loaders, question core maintainers.

but if decided current behavior acceptable, @ minimum both pep 8 , import documentation should have explanation of corner case , how can solved relative imports.


Comments

Popular posts from this blog

html - Outlook 2010 Anchor (url/address/link) -

javascript - Why does running this loop 9 times take 100x longer than running it 8 times? -

Getting gateway time-out Rails app with Nginx + Puma running on Digital Ocean -