The path based finder is responsible for finding and loading Python modules and packages whose location is specified with a string path entry . Most path entries name locations in the file system, but they need not be limited to this. As a meta path finder, the path based finder implements the$_{find_spec()}$ protocol previously described, however it exposes additional hooks that can be used to customize how modules are found and loaded from the import path . Three variables are used by the path based finder , sys.path , $_{sys.path_hooks}$and sys. path_importer_cache . The __path__ attributes on package objects are also used. These provide additional ways that the import machinery can be customized. sys.path contains a list of strings providing search locations for modules and packages. It is initialized from the PYTHONPATH environment variable and various other installation- and implementation-specific defaults. Entries in sys.path can name directories on the file system, zip files, and potentially other “locations” (see the site module) that should be searched for modules, such as URLs, or database queries. Only strings and bytes should be present on sys.path ; all other data types are ignored. The encoding of bytes entries is determined by the individual path entry finders . The path based finder is a meta path finder , so the import machinery begins the import path search by calling the path based finder’s find_spec() method as described previously. When the path argument to find_spec() is given, it will be a list of string paths to traverse - typically a package’s __path__ attribute for an import within that package. If the$_{path}$ argument is$_{None}$ , this indicates a top level import and$_{sys.path}$is used. The path based finder iterates over every entry in the search path, and for each of these, looks for an appropriate path entry finder ($_{PathEntryFinder}$ ) for the path entry. Because this can be an expensive operation (e.g. there may be stat() call overheads for this search), the path based finder maintains a cache mapping path entries to path entry finders. This cache is maintained in$_{sys.path_importer_cache}$ (despite the name, this cache actually stores finder objects rather than being limited to importer objects). In this way, the expensive search for a particular path entry location’s path entry finder need only be done once. User code is free to remove cache entries from sys.path_importer_cache forcing the path based finder to perform the path entry search again$^{3}$. If the path entry is not present in the cache, the path based finder iterates over every callable in$_{sys.path_hooks}$ . Each of the path entry hooks in this list is called with a single argument, the path entry to be searched. This callable may either return a path entry finder that can handle the path entry, or it may raise$_{ImportError}$. An$_{ImportError}$ is used by the path based finder to signal that the hook cannot find a path entry finder for that path entry . The exception is ignored and import path iteration continues. The hook should expect either a string or bytes object; the encoding of bytes objects is up to the hook (e.g. it may be a file system encoding, UTF-8, or something else), and if the hook cannot decode the argument, it should raise$_{ImportError}$. If $_{sys.path_hooks}$iteration ends with no path entry finder being returned, then the path based finder’s find_spec() method will store$_{None}$ in$_{sys.path_importer_cache}$ (to indicate that there is no finder for this path entry) and return$_{None}$ , indicating that this meta path finder could not find the module. If a path entry finder is returned by one of the path entry hook callables on$_{sys.path_hooks}$ , then the following protocol is used to ask the finder for a module spec, which is then used when loading the module. The current working directory – denoted by an empty string – is handled slightly differently from other en- tries on sys.path . First, if the current working directory is found to not exist, no value is stored in sys. path_importer_cache . Second, the value for the current working directory is looked up fresh for each module lookup. Third, the path used for$_{sys.path_importer_cache}$ and returned by$_{importlib.machinery.}$ PathFinder.find_spec() will be the actual current working directory and not the empty string. 3 In legacy code, it is possible to find instances of imp.NullImporter in the sys.path_importer_cache . It is recommended that code be changed to use None instead. See portingpythoncode for more details. Chapter 5. The import system 58 5.5.1 Path entry finders The Python Language Reference, Release 3.9.5