1

I'm using Python for a weeks now and i'm confronted to an issue with dynamic import. I have a file Test.py that in which a class is defined. I would like to use this class after the dynamic import of Test.py from another file.

My final goal is more complex but I simplified it but i still get the same problem.

File : Test.py

class Test :
    def __init__ ( self ) :
        print ( "instance" )

File : Main.py

def allImports ( ) :
    __import__ ( "Test" )

What i get :

>>> import Main
>>> Main.allImports()
>>> myInstance = Test ()
Traceback (most recent call last):
   File "<stdin>", line 1, in <module>
NameError: name 'Test' is not defined

I cannot specify in the fromlist which element from Test.py i have to import because i'm not supposed to know them.

What should i do ?

4
  • 1
    Wouldn't your code only import the module "Test" into the local scope of the function allImports()? Commented Jul 5, 2012 at 13:04
  • Actually the code i posted does but i would like to be able to use the class Test anywhere without any prefix. Commented Jul 5, 2012 at 13:20
  • That might be a little fiddly. Can you assume that the module will contain a single class with the same name as the module? Commented Jul 5, 2012 at 13:27
  • No @millimoose, sometimes the module will contain more than one class Commented Jul 5, 2012 at 13:29

4 Answers 4

3

For a solution closer to your intent:

import importlib
def allImports(globals):
    mod = importlib.import_module('Test', globals['__name__'])

    try:
        keys = mod.__all__
    except AttributeError:
        keys = dir(mod)

    for key in keys:
        if not key.startswith('_'):
            globals[key] = getattr(mod, key)

# …

allImports(globals())
Test # should work, you can also look into dir(Test) to find the class.

If your module doesn't have an __all__ the code above /will/ clobber your namespace something fierce. Either make sure you define __all__, or modify allImports() to only import the things you want. (E.g. only classes, or only classes defined in the module. This part really depends on your use case.)

Sign up to request clarification or add additional context in comments.

6 Comments

@millimose, don't you know how to make the class usable without prefixing the module name ?
@ibi0tux I changed the code to do something kinda sorta maybe similar to from Test import *. You should probably take caution so you only really import the things you want from a module using it.
Ty. This seems to work but i don't understand what's the problem with all.
If you import any modules into the Test module, but don't specify __all__, then from Test import * will re-export those modules. This means that you're going to reexport a whole lot of crap that you probably didn't mean to. Same goes for helper functions or classes that people using your module don't need / shouldn't use. __all__ means "these things are interesting to people using this module", and defining it is a best practice.
@millimose, i tried this to import packages but this fails when a file from the package imports another one. Is the problem due to the relative path which is not based on the package's root ?
|
1

When using __import__() to load a module, you have to look it up in sys.modules:

>>> import sys
>>> import Main
>>> Main.allImports()
>>> myInstance = sys.modules['Test'].Test()
instance
>>>

More information in the documentation and here, here, and here.

Comments

1

this code makes __import__ ( "Test" ) a local variable, so you can't access it outside the function.

   def allImports ( ) :
        __import__ ( "Test" )

try:

def allImports ( ) :
   test= __import__ ( "Test" )
   return test   #return the module

>>> import Main
>>> x=Main.allImports()  #store the returned module in x
>>> myInstance = x.Test ()
instance
>>>myInstance
<Test.Test instance at 0x011D7F80>

3 Comments

Thank you, but how should i use this returned variable ?
@user1504016 store it in some variable(x here), I edited my solution.
This way seems easier, but i would like to know if there is any way to import class in the global scope so that it can be used without prefixing with the scope name.
1

__import__ doesn't modify magically neither global nor local namespaces.

Modules and classes are first class citizens in Python i.e., you can use them as any other object in Python (bind to a name, pass as a parameter to a function, return as a value from a function).

def allImports():
    return __import__("Test")

Test_module = allImports()
Test = Test_module.Test # class
test_instance = Test()

If the above code is inside a function then to put Test into global namespace: globals()['Test'] = Test. Note most probably you don't need it and there are better ways to do whatever you want without modifying global namespace inside a function.

Usage of __import__() is discouraged use importlib.import_module() instead.

If the name of the module and the class are known you could just write at the module level:

from Test import Test

3 Comments

Ok. Thank you. The problem is that neither the name of the module and the name of the classes are known. The name of the module is a variable and i want to import all the module content (classes and functions).
@ibi0tux: you could get all classes and functions using inspect.getmembers() and inspect.isclass(), inspect.isfunction predicates. If you're creating some kind of plugin system; consider using an existing one such as yapsy
yes, i'm working about a plugin system but it is very basic so i didn't look for existing systems.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.