0

I'm new with Python and I'm trying to use classes to program using objects as I do with C++.

I wrote 3 .py files.

a.py

from b import *

class A:
    def __init__(self):
        self.m_tName = "A"

    def test(self):
        tB = B()

        tB.do( self )

b.py

from a import *

class B:
    def __init__(self):
        self.m_tName = "B"

    def do(self, tA ):
        if not isinstance( tA, A ):
            print ( "invalid parameter" )

        print( "OK" )

demo.py:

from a import *

if __name__ == "__main__":
    tA = A()

    tA.test()

As you can see I want to use a A() object to call the member function test() that creates a B() object and call the member function do() that uses a A() object.

So in B::do() I want to check the parameters using the built-in function isinstance(). But python tells me that there's a NameError: global name 'A' is not defined.

The A() class file is imported at the top of the b.py file.

Does anyone know what I'm doing wrong here ?

A.G.
  • 1,279
  • 1
  • 11
  • 28
  • 3
    You seem to have a circular dependency. `a.py` imports `b` and `b.py` imports `a`. – Cory Kramer Feb 16 '15 at 13:24
  • Yes there is a circular dependcy. C++ can handle it but I don't know it but I don't know if python can handle it. – A.G. Feb 16 '15 at 13:25
  • C++ can not "handle" circular dependencies either. You can just avoid them with careful use of forward declarations and include guards. – Cory Kramer Feb 16 '15 at 13:26
  • Ok if you prefer, there's a workaround in C++ using class A; before the Class B declaration. But is it possible to do so with python ? – A.G. Feb 16 '15 at 13:29
  • 1
    Python can usually handle circular dependencies (as long as you don't use the imported modules in top-level code), but not when you do `from x import *`. – interjay Feb 16 '15 at 13:30
  • @interjay: According to this article http://effbot.org/zone/import-confusion.htm, as you mentioned, circular dependencies can get fixed by importing modules at the end of the module. I have to keep in mind that python is an interpreted language in contrary of C++ that can easily handle circular dependencies since it's a compiled language with a final linking stage that resolves these kind of dependencies. – A.G. Feb 16 '15 at 13:41

2 Answers2

1

As pointed in some comment, circular dependencies are not well handled if imported in the form from a import A.

In short, the problem with ... import * is that is causes the local scope to have all its declarations overridden, in effect making the identification of from which module (in your case) a class comes from. This causes exactly what you are facing.

Changing the import statement in the following way, together with a classified reference to a.A, produces OK as output.

import a

class B:
    def __init__(self):
        self.m_tName = "B"

    def do(self, tA ):
        print tA
        if not isinstance( tA, a.A ):
            print ( "invalid parameter" )

        print( "OK" )

As a bit of additional information, this has already been discussed in Why is "import *" bad?. I would point in special to this answer: https://stackoverflow.com/a/2454460/1540197.

**Edit:**This article explain the import confusion.

Community
  • 1
  • 1
h7r
  • 4,944
  • 2
  • 28
  • 31
0

You have a circular dependancy, a.py and b.py import each other.

You could move either import statement inside the method where it is used. So b.py would become:

class A:
    def __init__(self):
        self.m_tName = "A"

    def test(self):
        from b import B
        tB = B()

        tB.do( self )
camz
  • 605
  • 3
  • 15
  • This fix does not fully work. It works but python produces a warning during execution. – A.G. Feb 17 '15 at 07:34