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:
- combine model code single file: having 20+ classes in same file far worse style trying (with separate files), in opinion.
- 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
Post a Comment