Skip to content Skip to sidebar Skip to footer

Package __init__.py Import All Subfiles, But Only Load One From Another Script?

I have created a package with the following file structure: - package - __init__.py - load.py - train.py - test.py My __init__.py file is simply an import of classes for t

Solution 1:

Here's a way to do something very close what you want. Instead of unconditionally importing all the package's classes in your __init__.py, you can define a function in it to explicitly import any of the ones desired (or all of them if none are specified).

__init__.py:

from pathlib import Path
import sys

print(f'In {Path(__file__).name}')

package_name = Path(__file__).parent.name
package_prefix = package_name + '.'
class_to_module_map = {'Load': 'load', 'Train': 'train', 'Test': 'test'}


defimport_classes(*class_names):
    namespace = sys._getframe(1).f_globals  # Caller's globals.ifnot class_names:
        class_names = class_to_module_map.keys()  # Import them all.for class_name in class_names:
        module = class_to_module_map[class_name]
        temp = __import__(package_prefix+module, globals(), locals(), [class_name])
        namespace[class_name] = getattr(temp, class_name)  # Add to caller's namespace.

For testing purposes, here's what I put in the load.py script: (I also put something similar in the other two modules in order to verify whether or not they were getting imported.)

load.py:

from pathlib import Path

print(f'In {Path(__file__).name}')

classLoad: pass

And finally here's a example of using it to only import the Load class:

ad_hoc.py:

from my_package import import_classes

#from my_package import Load
import_classes('Load')

test = Load()
print(test)

Along with the output produced:

In __init__.py
In load.py
<my_package.load.Load object at 0x001FE4A8>

Solution 2:

Inside a folder oranges\, this is our __init__.py file:

__all__ = []

from pathlib import Path
from importlib import import_module
from sys import modules

package = modules[__name__]
initfile = Path(__file__)
for entry in initfile.parent.iterdir():
    is_file = entry.is_file()
    is_pyfile = entry.name.endswith('.py')
    is_not_initpy = (entry != initfile)
    if is_file and is_pyfile and is_not_initpy:
        module_name = entry.name.removesuffix('.py')
        module_path = __name__ + '.' + module_name
        module = import_module(module_path)
        setattr(package, module_name, module)
        __all__.append(module_name)

When we do from oranges import *, the code inside oranges\__init__.py cycles through the *.py files inside oranges\ (except __init__.py), and for each .py file does the following:

  • imports the .py file as a module into the variable module using Python's importlib.import_module

  • sets the module as a variable within the __init__.py file (or, more correctly, within the oranges package) using Python's setattr

  • finally, appends the module to the __all__ list

Post a Comment for "Package __init__.py Import All Subfiles, But Only Load One From Another Script?"