Friday, April 29, 2011

Importing In Python

Is it possible to import modules based on location?

(eg. do all modules i import have to be in /usr/lib64/python2.5/ or a similar dir?)

I'd like to import a module that's local to the current script.

From stackoverflow
  • You can edit your PYTHONPATH to add or remove locations that python will search whenever you attempt an import.

    • python will import from the current directory by default.

    • sys.path is the variable that controls where python searches for imports.

  • You can extend the path at runtime like this:

    sys.path.extend(map(os.path.abspath, ['other1/', 'other2/', 'yourlib/']))
    
  • You can import module that are in the same path the module you are importing to. For example:

    Directory contains: mod1.py, mod2.py

    mod2.py
    --------
    import mod1
    

    Or you can add any directory to your PYTHON_PATH variable:

    import sys
    sys.path.extend('/user/some/other/directory')
    import mod1
    
  • It searches in ./lib by default.

  • For low-level control over the import process, the imp module lets you import modules from arbitrary open files under arbitrary names.

    For example, if this is foo.py:

    def x():
        print 'hello, world'
    

    Then this code:

    import imp
    
    with open('foo.py', 'r') as module_file:
        imp.load_module('module_name', module_file, '', ('', 'r', imp.PY_SOURCE))
    
    import module_name
    
    module_name.x()
    

    prints "hello, world".

  • Use init.py

    The only problem with doing dynamic modification of sys.path is that you need to repeat it in every script and hard-code the pathnames. That gets messy and non DRY if you have even two or three files.

    Instead, if your file structure looks like this:

    ~/foo/__init__.py
    ~/foo/foo.py
    ~/foo/bar/__init__.py
    ~/foo/bar/baz.py
    

    Here the init.py's are blank files created with touch, while foo.py and baz.py are actual python scripts. Then you can do something like this:

    import sys
    try:
        from foo import foo
        from foo.bar import baz
    except ImportError:
        "%s is not in %s. Add to your PYTHONPATH in ~/.bashrc" % \
        (os.path.expanduser("~/foo"),sys.path)
    

    Structuring your stuff as a package from the beginning is a little more work but makes it much easier to scale the project later and to see where imports are coming from. Moreover, if you move stuff around, you can use a single symlink rather than doing a find/replace through your codebase. E.g. if you moved '~/foo' to '~/downloads/foo', just do this:

    cd ~
    ln -s ~/downloads/foo foo
    

    And all your imports will still work.

0 comments:

Post a Comment