views:

275

answers:

6

For the following Python code:

first.py

# first.py
from second import Second

class First:
    def __init__(self):
        print 'Second'

second.py

# second.py
from first import First

class Second:
    def __init__(self):
        print 'Second'

After creating the files and running the following from the shell:

python first.py

I get the error: ImportError: cannot import name Second

Do other dynamic languages like Ruby have this kind of issue? The reason I'm asking is because I'm encountering this issue in a Django project where 2 models depend on each other. I know that the possible solutions are re-designing the project or import on demand. I just want to know if devs in other dynamic languages have experienced this issue.

+9  A: 

Python can handle circular imports to some extent. In cases where no sense can be made, the solution would probably still not make sense in another language. Most of the problems can be cleared up by using import first and later referring to first.First instead of from first import First.

It would be better if you could move shared code off to its own module or somehow refactor out the need for a circular import. Circular imports always indicate a design problem.

Mike Graham
So if I want to split off thousands of lines of code into multiple files, it's a design problem?
asmeurer
When you split code from one file into multiple files which rely on circular imports, you've not done it with an optimal design.
Mike Graham
+3  A: 

Recursive definitions are not a problem restricted to dynamic languages. It's also often an issue in statically types languages. It might show up as a compile error because one of the types will be used before it is defined.

In some languages the solution is to use forward declarations. Other languages solve the problem by compiling more than one file at once.

In Python you can solve the problem by moving the imports from the top level into the functions where they are needed. Also, a circular reference isn't actually an error, so if you are careful, you can make it work anyway.

Mark Byers
A: 

This isn't a problem related to "dynamic" languages. It's an architectural issue. You need to take a better look at how you've structured things.

Chris Lively
+1  A: 

Logically this is a paradox. It's the chicken and egg issue in code form. One of them has to come first. As suggested by the others, please go back to the drawing board and you'll be better off for it in the long run. Languages prevent you from doing this stuff for a reason!

jathanism
It might be a bad idea, but it isn't a paradox to have two modules depend on each other.
Draemon
To depend on each other incrementally, perhaps, but distinctly as suggested in the OP? Paradox.
jathanism
No it's not. Haven't you ever heard of recursion?
asmeurer
Recursive functions, absolutely. Recursive modules? Never.
jathanism
@jathanism, if two functions in different files recursively call each other, you will get this problem. The solution is to import one from inside the other. Just because two functions are in different files, doesn't mean that they are in different modules. It just means that they are somehow logically separate, or because combining them would make a file that is too large.
asmeurer
+1  A: 

All other posters are correct that circular imports are a serious issue that you should fix, structurally.

However, specificly with Python/Django models, you can use string names to setup foreign keys to avoid these circular dependency issues --

#appA/models.py
class A(models.Model):
  b = models.ForeignKey('appB.b')

#appB/models.py
class B(models.Model):
  a = models.ForeignKey('appA.a')

Circular references in DB tables aren't necessarily a bad thing (but aren't always good); Django allows for definition of keys with a string to help in situations where it's necessary. If you actually need to instantiate the two classes inside one another, you've got bigger problems.

linked
+1  A: 

Note that if you just move your imports to the end of your module, circular imports will work as expected. Like so:

first.py

# first.py
class First:
  def __init__(self):
    print 'Second'
from second import Second

second.py

# second.py
class Second:
    def __init__(self):
        print 'Second'
from first import First

Fredrik Lundh's import reference is worth a read. As others have advised, though, you're best off rejiggering your code to avoid circular imports entirely.

zenbot