Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Importing classes from different files in a subdirectory

Tags:

Here's the structure I'm working with:

directory/           script.py           subdir/                  __init__.py                  myclass01.py                  myclass02.py 

What I want to do is import in script.py the classes defined in myclass01.py and myclass02.py. If I do:

from subdir.myclass01 import * 

It works fine for the class defined in myclass01.py. But with this solution if there are many classes defined in different files in subdir and I want to import all of them, I'd have to type one line for each file. There must be a shortcut for this. I tried:

from subdir.* import * 

But it didn't work out.

EDIT: here are the contents of the files:

This is __init__.py (using __all__ as Apalala suggested):

__all__ = ['MyClass01','MyClass02'] 

This is myclass01.py:

class MyClass01:     def printsomething():         print 'hey' 

This is myclass02.py:

class MyClass02:     def printsomething():         print 'sup' 

This is script.py:

from subdir import * MyClass01().printsomething() MyClass02().printsomething() 

This is the traceback that I get when I try to run script.py:

File "script.py", line 1, in <module>     from subdir import * AttributeError: 'module' object has no attribute 'MyClass01' 
like image 487
liewl Avatar asked Feb 27 '11 18:02

liewl


People also ask

Can you import a class from another file in Python?

Python modules can get access to code from another module by importing the file/function using import. The import statement is that the commonest way of invoking the import machinery, but it's not the sole way. The import statement consists of the import keyword alongside the name of the module.

Does Python search subdirectories for import?

The PYTHONPATH is the environment variable that contains the path of the directories that Python searches to import the packages. Therefore, if we add the subdirectory to the PYTHONPATH , Python will first look at the directories in PYTHONPATH and import it from there.

How do I import a module from the outside directory?

Method 1: Using sys. The sys. path variable of the module sys contains the list of all directories in which python will search for a module to import. We can directly call this method to see the directories it contains. So for importing mod.py in main.py we will append the path of mod.py in sys.


1 Answers

Although the names used there are different from what's shown in your question's directory structure, you could use my answer to the question titled Namespacing and classes. The __init__.py shown there would have also allowed the usepackage.py script to have been written this way (package maps to subdir in your question, and Class1 to myclass01, etc):

from package import *  print Class1 print Class2 print Class3 

Revision (updated):

Oops, sorry, the code in my other answer doesn't quite do what you want — it only automatically imports the names of any package submodules. To make it also import the named attributes from each submodule requires a few more lines of code. Here's a modified version of the package's __init__.py file (which also works in Python 3.4.1):

def _import_package_files():     """ Dynamically import all the public attributes of the python modules in this         file's directory (the package directory) and return a list of their names.     """     import os     exports = []     globals_, locals_ = globals(), locals()     package_path = os.path.dirname(__file__)     package_name = os.path.basename(package_path)      for filename in os.listdir(package_path):         modulename, ext = os.path.splitext(filename)         if modulename[0] != '_' and ext in ('.py', '.pyw'):             subpackage = '{}.{}'.format(package_name, modulename) # pkg relative             module = __import__(subpackage, globals_, locals_, [modulename])             modict = module.__dict__             names = (modict['__all__'] if '__all__' in modict else                      [name for name in modict if name[0] != '_'])  # all public             exports.extend(names)             globals_.update((name, modict[name]) for name in names)      return exports  if __name__ != '__main__':     __all__ = ['__all__'] + _import_package_files()  # '__all__' in __all__ 

Alternatively you can put the above into a separate .py module file of its own in the package directory—such as _import_package_files.py—and use it from the package's __init__.py like this:

if __name__ != '__main__':     from ._import_package_files import *  # defines __all__     __all__.remove('__all__')  # prevent export (optional) 

Whatever you name the file, it should be something that starts with an _ underscore character so it doesn't try to import itself recursively.

like image 195
martineau Avatar answered Sep 21 '22 15:09

martineau