简体   繁体   中英

Using importlib.import_module over an import statement

I was using an api -- smartsheet-python-sdk that was running fine when executed from the source code. However, when I went to package using PyInstaller I was getting an error because PyInstaller couldn't find the necessary modules. In the smartsheet library it is using importlib.import_module to import modules from the library.

    def __getattr__(self, name):
        """
        Handle sub-class instantiation.

        Args:
            name (str): Name of smartsheet to instantiate.

        Returns:
            Instance of named class.
        """
        try:
            # api class first
            class_ = getattr(importlib.import_module(
                __package__ + '.' + name.lower()), name)
            return class_(self)
        except ImportError:
            # model class next:
            try:
                class_ = getattr(importlib.import_module(
                    name.lower()), name)
                return class_()
            except ImportError:
                self._log.error(
                    'ImportError! Could not load api or model class %s', name)
                return name

Is there any objective benefit to using something like this when it is only importing modules from its own library as opposed to just adding Import Statements to known modules?

There's a few different reasons why this approach can be advantageous from a practical standpoint.

Convenience

Explicitly listing modules requires additional steps that must be performed to integrate a new module. This step of declaring your import can be omitted entirely.

Less Prone To Errors

If new modules are added infrequently, forgetting to import the module in the correct location is one of those simple little mistakes that can occur. Removing that requirement means that mistake cannot happen. Will this approach have other downsides instead? Sure, but the weight of those tradeoffs is subjective.

Extensibility

In a comment you wrote

I just don't see the reason this particular case would need that since it will only ever be referring to its own modules.

This is a faulty assumption. It is entirely possible a module may come from another location at some future point. Unlikely? Maybe, but this design allows for more easily adding a new possible location - here two locations are used, a third is certainly possible. Maybe mocks are used for testing purposes, for example. Certainly there are other approaches that can work, but this seems to be a possible reason for this approach.

But What About PyInstaller?

Ultimately, you are correct that this approach makes it difficult to easily load into PyInstaller. From their documentation , there are some workarounds that you can apply to the scripts of your build process. (Copied here for convenience)

Some Python scripts import modules in ways that PyInstaller cannot detect: for example, by using the __import__() function with variable data, using imp.find_module() , or manipulating the sys.path value at run time. If your script requires files that PyInstaller does not know about, you must help it:

  • You can give additional files on the pyinstaller command line.
  • You can give additional import paths on the command line.
  • You can edit the myscript.spec file that PyInstaller writes the first time you run it for your script. In the spec file you can tell PyInstaller about code modules that are unique to your script.
  • You can write “hook” files that inform PyInstaller of hidden imports. If you create a “hook” for a package that other users might also use, you can contribute your hook file to PyInstaller.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM