[Python-Dev] relative import circular problem

Guido van Rossum guido at python.org
Thu Apr 4 17:17:01 CEST 2013


On Thu, Apr 4, 2013 at 2:36 AM, Kristján Valur Jónsson <
kristjan at ccpgames.com> wrote:
[...]

> There can be good and valid reasons to put things that depend on each
> other in separate modules, for example when trying to separate modules by
> functionality or simply when splitting a long file into two.
> Notice that cyclic dependencies are allowed _within_ a module file.
>  Imagine if we decided that we could only refer to objects _previously_
>  declared within a .py file, because it encouraged the good design practice
> of factoring out common dependencies.
> Dependency graphs of software entities can sadly not always be reduced
> into a DAG, and we should, IMHO, by no means force people to keep each
> cygle in the dependency graph within a single .py module.
>

IMO in both cases (cyclic dependencies within modules and between modules)
Python's approach is consistently derived from a specific implementation
strategy: names are available after they are defined. This works (at least
it doesn't raise NameError :-):

def f(): return g()
def g(): return f()
f()

Because by the time f() is called, g() is defined. Note that this doesn't
work:

def f(): return g()
f()
def g(): return f()

IOW there is no magic. If you think of putting objects in a dictionary, the
semantics are clear. (Except for the shenanigans that the compiler carries
out for determining whether something is a local variable reference or not,
but that's also explainable.)

This does not work:

a = b
b = a

because the first line references b which is not yet defined.

Similarly, if module A imports module B and B imports A, that works because
imports are first satisfied from sys.modules, and when A is loaded, it is
entered into sys.modules before its code is executed. But it may be that if
A is loaded and starts importing B, B is then loaded and imports A, which
finds A in the state it reached when it decided to import B. The rules here
are more complicated because of what "from A import X" means (it depends on
whether X is a submodule or not) but there are rules, and they are totally
well-defined. The final piece of this puzzle is that, given A and B
mutually importing each other, the top-level app code could start by
importing A or B, and the execution order will be different then. (You can
force this by putting A and B in a package whose __init__.py imports them
in the desired order.)

I don't really see what we could change to avoid breaking code in any
particular case -- the burden is up to the library to do it right. I don't
see a reason to forbid any of this either.

-- 
--Guido van Rossum (python.org/~guido)
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-dev/attachments/20130404/f097a7cd/attachment.html>


More information about the Python-Dev mailing list