Importing classes from different files in a subdirectory

前端 未结 5 1293
深忆病人
深忆病人 2020-11-29 07:21

Here\'s the structure I\'m working with:

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


        
相关标签:
5条回答
  • 2020-11-29 07:50

    I know it's been a couple months since this question was answered, but I was looking for the same thing and ran across this page. I wasn't very satisfied with the chosen answer, so I ended up writing my own solution and thought I'd share it. Here's what I came up with:

    # NOTE: The function name starts with an underscore so it doesn't get deleted by iself
    def _load_modules(attr_filter=None):
        import os
    
        curdir = os.path.dirname(__file__)
        imports = [os.path.splitext(fname)[0] for fname in os.listdir(curdir) if fname.endswith(".py")]
    
        pubattrs = {}
        for mod_name in imports:
            mod = __import__(mod_name, globals(), locals(), ['*'], -1)
    
            for attr in mod.__dict__:
                if not attr.startswith('_') and (not attr_filter or attr_filter(mod_name, attr)):
                    pubattrs[attr] = getattr(mod, attr)
    
        # Restore the global namespace to it's initial state
        for var in globals().copy():
            if not var.startswith('_'):
                del globals()[var]
    
        # Update the global namespace with the specific items we want
        globals().update(pubattrs)
    
    # EXAMPLE: Only load classes that end with "Resource"
    _load_modules(attr_filter=lambda mod, attr: True if attr.endswith("Resource") else False)
    del _load_modules # Keep the namespace clean
    

    This simply imports * from all .py files in the package directory and then only pulls the public ones into the global namespace. Additionally, it allows a filter if only certain public attributes are desired.

    0 讨论(0)
  • 2020-11-29 07:51

    Your best option, though probably not the best style, is to import everything into the package's namespace:

    # this is subdir/__init__.py
    from myclass01 import *
    from myclass02 import *
    from myclass03 import *
    

    Then, in other modules, you can import what you want directly from the package:

    from subdir import Class1
    
    0 讨论(0)
  • 2020-11-29 07:54
    from subdir.* import *
    

    You can not use '*' this way directly after the 'from' statement. You need explict imports. Please check with the Python documentation on imports and packages.

    0 讨论(0)
  • 2020-11-29 08:03

    I use this simple way:

    1. add the directory to the system path, then
    2. import module or from module import function1, class1 in that directory.

    notice that the module is nothing but the name of your *.py file, without the extension part.

    Here is a general example:

    import sys
    sys.path.append("/path/to/folder/")
    import module # in that folder
    

    In your case it could be something like this:

    import sys
    sys.path.append("subdir/")
    import myclass01
    # or
    from myclass01 import func1, class1, class2 # .. etc
    
    0 讨论(0)
  • 2020-11-29 08:13

    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.

    0 讨论(0)
提交回复
热议问题