Thread: Circular import

    #1
  1. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Sep 2012
    Posts
    5
    Rep Power
    0

    Circular import


    Is it allowed to have a circular import stucture, simplified with the example below?

    Code:
    
    # Module A:
    import C
    
    # Module B:
    import A
    
    # Module C:
    import B
    
    # Main :
    import A
    import B
    import C
    
    As I see it, it only requires an extra compilation of A. Is it wrong? What could happen if there are some circular imports? It is very hard, in my case, to get a good program structure that has no circular imports.
  2. #2
  3. Contributing User
    Devshed Demi-God (4500 - 4999 posts)

    Join Date
    Aug 2011
    Posts
    4,837
    Rep Power
    480
    It appears that python recursively loads the modules.
    Code:
    $ ( cd /tmp && python -c 'import A' )
    importing A line 1
    importing C line 1
    importing B line 1
    finishing B import
    finishing C import
    finishing A import
    $ ( cd /tmp && for a in A B C ; do echo $a.py && cat $a.py ; done )
    A.py
    print('importing A line 1')
    import C
    print('finishing A import')
    B.py
    print('importing B line 1')
    import A
    print('finishing B import')
    C.py
    print('importing C line 1')
    import B
    print('finishing C import')
    $


    Now, suppose I stick an error (not a syntax error) into A.

    print('importing A line 1')
    import C
    1/0 # error
    print('finishing A import')


    Then it turns out that sys.modules contains entries for B and for C but not A .

    Code:
    $ ( cd /tmp && python -ic 'import sys,A' )
    importing A line 1
    importing C line 1
    importing B line 1
    finishing B import
    finishing C import
    Traceback (most recent call last):
      File "<string>", line 1, in <module>
      File "A.py", line 3, in <module>
        1/0 # error
    ZeroDivisionError: integer division or modulo by zero
    >>> print(sys.modules)
    {'apt.os': None, ..., 'B': <module 'B' from 'B.pyc'>, ... }
    Good luck.
    [code]Code tags[/code] are essential for python code and Makefiles!
  4. #3
  5. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Sep 2012
    Posts
    5
    Rep Power
    0

    Circular import, further testing



    Thank you for your effort. This inspired me to do some own testing more ressembling my case. In the test there are 3 modules, A.py, B.py and C.py. They are called from main.py. The import structure is circular. The modules has one (or two) functions each, a(), b(), c() and c1(). There are print outs att the beginning of each module and when importing is finished. There are also print outs when each routine starts running and is finished.
    Code:
    # Module A.py
    print 'start module A'
    import C
    print 'End import C in module A'
    
    def a() :
        print 'A.a() is running'
        C.c1()
        print 'In module A finish C.c1()'
        
    
    # Module B.py
    print 'start module B'
    import A
    print 'End import A in module B'
    
    def b() :
        print 'B.b() is running'
        A.a()
        print 'In module B finish B.b() and A.a()'
    
    
    # Module C.py
    print 'start module C'
    import A
    import B 
    print 'End import A, B in module C'
    
    def c() :
        print 'C.c() is running'
        A.a()
        B.b()
        print 'In module C finish A.a() and B.b()'
    
    def c1() :
        print 'C.c1() is running'
    
    
    # Module main.py
    import sys
    print 'start main'
    import A
    import B
    import C
    print 'End import A, B and C in module main'
    if True  :
        print 'running main'
        A.a()
        B.b()
        C.c()
        print 'In module main finish A.a(), B.b() and C.c()'
    
    #   Finding the modules in 'sys.modules'
        print
        sys_modules = sys.modules
        module_keys = sys_modules.keys()
        for mod in module_keys :
            if mod == 'A' or mod == 'B' or mod == 'C' or mod == '__main__' :
                print mod, ':', sys_modules[ mod ]
    
    
    ### The print out from this code is :
    
    start main
    start module A
    start module C
    start module B
    End import A in module B
    End import A, B in module C
    End import C in module A
    End import A, B and C in module main
    
    running main
    A.a() is running
    C.c1() is running
    In module A finish C.c1()
    B.b() is running
    A.a() is running
    C.c1() is running
    In module A finish C.c1()
    In module B finish B.b() and A.a()
    C.c() is running
    A.a() is running
    C.c1() is running
    In module A finish C.c1()
    B.b() is running
    A.a() is running
    C.c1() is running
    In module A finish C.c1()
    In module B finish B.b() and A.a()
    In module C finish A.a() and B.b()
    In module main() finish A.a(), B.b() and C.c()
    
    A : <module 'A' from '/Users/Sten/Programmering/Python/Train/Test import/A.pyc'>
    B : <module 'B' from '/Users/Sten/Programmering/Python/Train/Test import/B.pyc'>
    C : <module 'C' from '/Users/Sten/Programmering/Python/Train/Test import/C.pyc'>
    __main__ : <module '__main__' (built-in)>

    It seams to me that all works OK any comments?
    Thanks in advance
  6. #4
  7. Contributing User
    Devshed Demi-God (4500 - 4999 posts)

    Join Date
    Aug 2011
    Posts
    4,837
    Rep Power
    480
    Spell "seams" as "seems".

    More seriously, the test was fairly easy and we learned to "just try it". Actually, I was fairly sure beforehand, in fact rewrote my post after I tried it, that the circular import would work somewhat differently.
    Last edited by b49P23TIvg; September 27th, 2012 at 12:15 PM.
    [code]Code tags[/code] are essential for python code and Makefiles!

IMN logo majestic logo threadwatch logo seochat tools logo