python - Intra-package imports do not always work -


i have django project structured so:

appname/    models/       __init__.py       a.py       base.py       c.py 

... appname/models/__init__.py contains statements so:

from appname.models.base import base appname.models.a import appname.models.c import c 

... , appname/models/base.py contains:

import django.db.models   class base(django.db.models.model):    ... 

and appname/models/a.py contains:

import appname.models models   class a(models.base):    .... 

...and appname/models/c.py, etc..

i quite happy structure of code, of course not work, because of circular imports.

when appname/__init__.py run, appname/models/a.py run, module imports "appname.models", has not finished executing yet. classic circular import.

so supposedly indicates code structured poorly , needs re-designed in order avoid circular dependency.

what options that?

some solutions can think of , why don't want use them:

  1. combine model code single file: having 20+ classes in same file far worse style trying (with separate files), in opinion.
  2. move "base" model class package outside of "appname/models": means end package in project contains base/parent classes should ideally split packages in child/sub classes located. why should have base/parent classes models, forms, views, etc. in same package , not in own packages (where child/sub classes located), other avoid circular imports?

so question not how avoid circular imports, in way clean (if not cleaner) tried implement.

does have better way?

edit

i have researched more thoroughly , come conclusion bug in either core python or python documentation. more information available at question , answer.

python's pep 8 indicates clear preference absolute on relative imports. problem has workaround involves relative imports, , there possible fix in import machinery.

my original answer below gives examples , workarounds.

original answer

the problem, have correctly deduced, circular dependencies. in cases, python can handle these fine, if many nested imports, has issues.

for example, if have 1 package level, hard break (without mutual imports), nest packages, works more mutual imports, , starts become difficult make work. here example provokes error:

level1/__init__.py

    level1.level2 import base 

level1/level2/__init__.py

    level1.level2.base import base     level1.level2.a import 

level1/level2/a.py

    import level1.level2.base     class a(level1.level2.base.base): pass 

level1/level2/base

    class base: pass 

the error can "fixed" (for small case) in several different ways, many potential fixes fragile. example, if don't need import of a in level2 __init__ file, removing import fix problem (and program can later execute import level1.level2.a.a), if package gets more complex, see errors creeping in again.

python job of making these complex imports work, , rules when , won't work not @ intuitive. 1 general rule from xxx.yyy import zzz can more forgiving import xxx.yyy followed xxx.yyy.zzz. in latter case, interpreter has have finished binding yyy xxx namespace when time retrieve xxx.yyy.zzz, in former case, interpreter can traverse modules in package before top-level package namespace set up.

so example, real problem bare import in a.py fixed:

    level1.level2.base import base     class a(base): pass 

consistently using relative imports way enforce use of from ... import simple reason relative imports not work without from'. use relative imports example above,level1/level2/a.py` should contain:

from .base import base class a(base): pass 

this breaks problematic import cycle , else works fine. if imported name (such base) confusingly generic when not prefixed source module name, can rename on import:

from .base import base basemodel class a(basemodel): pass 

although fixes current problem, if package structure gets more complex, might want consider using relative imports more generally. example, level1/level2/__init__.py be:

from .base import base .a import 

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 -