Python import as global name not defined

23,638

Solution 1

In Python, each module has it's own global namespace. When you do an import, you're only adding the imported modules to the current module's namespace, not to the namespace of any other module. If you want to put it in another namespace, you need to tell Python this explicitly.

main.py:

if db == "mysql": # or whatever your real logic is
    import mysql_db as db_util
elif db == "postgres":
    import postgres_db as db_util

import some_helper_module

some_helper_module.db_util = db_util # explicitly add to another namespace

#...

Other modules:

import some_helper_module

db = some_helper_module.db_util.connect() # or whatever the real API is

#...

Note that you can't usually use your main module (which is executed as a script) as a shared namespace. That's because Python uses the module's __name__ attribute to determine how to cache the module (so that you always get the same object from multiple imports), but a script is always given a __name__ of "__main__" rather than its real name. If another module imports main, they'll get a separate (duplicate) copy!

Solution 2

You're approaching the problem with the wrong point of view. Every module is a namespace that starts empty and is filled with a name for (typically) each statement it runs:

import foo                   => defines foo
from foo import bar          => defines bar
from foo import bar as baz   => defines baz
class kls:
    pass                     => defines kls
def fun():
    pass                     => defines fun
var = 6 * 7                  => defines var

Looking at ClassX.py we see that the name ca is not defined in this module, but ClassA and ClassC are. So the execution of the line xa=ca() from ClassX.py fails.

In general, the idea is that every single module imports what it needs. You can also patch a name "into" a module from outside, but this is generally considered very bad style (reserved for very special cases).

Share:
23,638

Related videos on Youtube

cswaim
Author by

cswaim

Updated on May 04, 2020

Comments

  • cswaim
    cswaim about 4 years

    I have an application that runs on Postgres & Mysql. Each program checks to determine the database and then imports either postgres_db as db_util or mysql_dt as db_util. All works well when code in main references db_util, but if a class is imported, the reference to db_util is not defined.

    I created the following to classes and main to test the problem and found another interesting side effect. Classes B & C reference ClassA under different import cases. B & C are identical except B is in main and C is imported.

    ClassX.py

    class ClassA(object):
        def print_a(self):
            print "this is class a"
    
    class ClassC(object):
        def ref_a(self):
            print 'from C ref a  ==>',
            xa=ClassA()
            xa.print_a()
        def ref_ca(self):
            print 'from C ref ca ==>',
            xa=ca()
            xa.print_a()
    

    test_scope.py

    from classes.ClassX import ClassA
    from classes.ClassX import ClassA as ca
    from classes.ClassX import ClassC as cb
    
    
    class ClassB(object):
        def ref_a(self):
            print 'from B ref a  ==>',
            xa=ClassA()
            xa.print_a()
        def ref_ca(self):
            print 'from B ref ca ==>',
            xa=ca()
            xa.print_a()
    
    print 'globals:',dir()
    print 'modules','ca:',ca,'cb:',cb,'CA:',ClassA
    print ''
    print 'from main'
    xb=ClassB()
    xb.ref_a()
    xb.ref_ca()
    
    print ''
    print 'from imports'
    xbs=cb()
    xbs.ref_a()
    xbs.ref_ca()
    

    And the results:

    globals: ['ClassA', 'ClassB', '__builtins__', '__doc__', '__file__', '__name__', '__package__', 'ca', 'cb']
    modules ca: <class 'classes.ClassX.ClassA'> cb: <class 'classes.ClassX.ClassC'> CA: <class 'classes.ClassX.ClassA'>
    
    from main
    from B ref a  ==> this is class a
    from B ref ca ==> this is class a
    
    from imports
    from C ref a  ==> this is class a
    from C ref ca ==>
    Traceback (most recent call last):
      File "test_scope.py", line 32, in <module>
        xbs.ref_ca()
      File "R:\python\test_scripts\scope\classes\ClassX.py", line 13, in ref_ca
        xa=ca()
    NameError: global name 'ca' is not defined
    Press any key to continue . . .
    

    From my test, I see that the object ca (imported as) is not available to the ClassC, however, the module ClassA is available (imported without as).

    1. Why the difference between import and import as behavior? I am unclear why mains globals are not available to classes main imports.
    2. What is a good approach to dynamically determine appropriate db_util module to import and have it accessible to other imported classes?

    Update: After reading yet another post on Namespaces: "Visibility of global variables from imported modules", I understand that in my example above the reason classA is available to ClassC is that A & C are in the same imported file, thus the same namespace.

    So the remaining question is a design question:

    if I have code like this:

    if db == 'MySQL':
        from mysql_db import db_util
    elif db == 'Postgres'
        from postgres_db import db_util
    

    What is a good approach to make db_util available to all imported modules?

    UPDATE:

    from the reponse by Blckknght, I added the code

    cb.ca =ca
    

    to the scope_test script. This requires the class call to xa=ca() be changed to xa=self.ca(). I also think that adding objects to a class from outside the class, though Python allows it, is not a good design methodology and will make debugging a nightmare.

    However, since I think modules and classes should be standalone or specifically declare their dependencies, I am going to implement the class like this, using the code sample from above.

    break out ClassA and ClassC to separate modules and at the top of ClassC, before the class definition, do the imports

    from ClassA import ClassA
    from ClassA import ClassA as ca
    
    class ClassB(object):
    

    and in my real situation, where I need to import the db_util module into several modules

    ci.py #new module to select class for appropriate db

    if db == 'MySQL':
        from mysql_db import db_util
    elif db == 'Postgres'
        from postgres_db import db_util
    

    in each module needing the db_util class

    import ci
    db_util=ci.db_util         #add db_util to module globals
    
    class Module(object):
    

    One problem with this is it requires each module using the db_util to import it, but it does make the dependencies known.

    I will close this question and want to thank Blckknght and Armin Rigo for their responses which help clarify this issue for me. I would appreciate any design related feedback.

  • cswaim
    cswaim about 11 years
    I added cb.ca =ca to my test_scope.py script above immediately after the imports, thinking that will add ca to the cb namespace. I am still getting global not defined and when I print the globals from the ClassC, it prints globals: ['self'] -- no reference to ca and the error still exists. What did I miss?
  • cswaim
    cswaim about 11 years
    I missed ca must be referenced as self.ca as ca is now defined within the class.