Автор оригинала: Doug Hellmann.
Большинство программ Python представляют собой комбинацию нескольких модулей, которые импортирует главное приложение. Независимо от того, используете ли вы функции стандартной библиотеки или организуете пользовательский код в отдельных файлах, чтобы упростить обслуживание, понимание и управление зависимостями для программы является важным аспектом разработки. sys
включает информацию о модулях, доступных приложению, либо как встроенных, либо после импорта. Он также определяет ловушки для переопределения стандартного поведения импорта для особых случаев.
Импортированные модули
sys.modules
– это словарь, сопоставляющий имена импортированных модулей с объектом модуля, содержащим код.
sys_modules.py
import sys import textwrap names sorted(sys.modules.keys()) name_text ', '.join(names) print(textwrap.fill(name_text, width64))
Содержимое sys.modules
изменяется по мере импорта новых модулей.
$ python3 sys_modules.py __main__, _abc, _bootlocale, _codecs, _collections, _collections_abc, _frozen_importlib, _frozen_importlib_external, _functools, _heapq, _imp, _io, _locale, _operator, _signal, _sre, _stat, _thread, _warnings, _weakref, abc, builtins, codecs, collections, contextlib, copyreg, encodings, encodings.aliases, encodings.latin_1, encodings.utf_8, enum, functools, genericpath, heapq, importlib, importlib._bootstrap, importlib._bootstrap_external, importlib.abc, importlib.machinery, importlib.util, io, itertools, keyword, marshal, operator, os, os.path, posix, posixpath, re, reprlib, site, sphinxcontrib, sre_compile, sre_constants, sre_parse, stat, sys, textwrap, types, warnings, zipimport
Встроенные модули
Интерпретатор Python может быть скомпилирован с некоторыми встроенными модулями C, поэтому их не нужно распространять как отдельные разделяемые библиотеки. Эти модули не отображаются в списке импортированных модулей, управляемых в sys.modules
, поскольку они не были импортированы технически. Единственный способ найти доступные встроенные модули – использовать sys.builtin_module_names
.
sys_builtins.py
import sys import textwrap name_text ', '.join(sorted(sys.builtin_module_names)) print(textwrap.fill(name_text, width64))
Вывод этого сценария будет отличаться, особенно если он запускается с настраиваемой версией интерпретатора. Этот вывод был создан с использованием копии интерпретатора, установленного из стандартного установщика python.org для OS X.
$ python3 sys_builtins.py _abc, _ast, _codecs, _collections, _functools, _imp, _io, _locale, _operator, _signal, _sre, _stat, _string, _symtable, _thread, _tracemalloc, _warnings, _weakref, atexit, builtins, errno, faulthandler, gc, itertools, marshal, posix, pwd, sys, time, xxsubtype, zipimport
Смотрите также
- Инструкции по сборке – Инструкции по сборке Python из README, распространяемого с исходным кодом.
Путь импорта
Путь поиска модулей управляется как список Python, сохраненный в sys.path
. Содержимое пути по умолчанию включает каталог сценария, использованного для запуска приложения, и текущий рабочий каталог.
sys_path_show.py
import sys for d in sys.path: print(d)
Первый каталог в пути поиска является домом для самого примера сценария. За этим следует ряд путей, зависящих от платформы, по которым могут быть установлены скомпилированные модули расширения (написанные на C), а затем глобальный каталог site-packages
отображается последним.
$ python3 sys_path_show.py /Users/dhellmann/Documents/PyMOTW/pymotw-3/source/sys .../python35.zip .../lib/python3.5 .../lib/python3.5/plat-darwin .../python3.5/lib-dynload .../lib/python3.5/site-packages
Список путей поиска импорта можно изменить перед запуском интерпретатора, установив для переменной оболочки PYTHONPATH
список каталогов, разделенных двоеточиями.
$ > python3 sys_path_show.py /Users/dhellmann/Documents/PyMOTW/pymotw-3/source/sys /my/private/site-packages /my/shared/site-packages .../python35.zip .../lib/python3.5 .../lib/python3.5/plat-darwin .../python3.5/lib-dynload .../lib/python3.5/site-packages
Программа также может изменять свой путь, добавляя элементы непосредственно в sys.path
.
sys_path_modify.py
import importlib import os import sys base_dir os.path.dirname(__file__) or '.' print('Base directory:', base_dir) # Insert the package_dir_a directory at the front of the path. package_dir_a os.path.join(base_dir, 'package_dir_a') sys.path.insert(0, package_dir_a) # Import the example module import example print('Imported example from:', example.__file__) print(' ', example.DATA) # Make package_dir_b the first directory in the search path package_dir_b os.path.join(base_dir, 'package_dir_b') sys.path.insert(0, package_dir_b) # Reload the module to get the other version importlib.reload(example) print('Reloaded example from:', example.__file__) print(' ', example.DATA)
При повторной загрузке импортированного модуля файл повторно импортируется, а для хранения результатов используется тот же объект module
. Изменение пути между начальным импортом и вызовом reload ()
означает, что другой модуль может быть загружен во второй раз.
$ python3 sys_path_modify.py Base directory: . Imported example from: ./package_dir_a/example.py This is example A Reloaded example from: ./package_dir_b/example.py This is example B
Пользовательские импортеры
Изменение пути поиска позволяет программисту контролировать поиск стандартных модулей Python. Но что, если программе необходимо импортировать код откуда-нибудь, кроме обычных файлов .py
или .pyc
в файловой системе? PEP 302 решает эту проблему, предлагая идею перехватчиков импорта. , что может отследить попытку найти модуль на пути поиска и принять альтернативные меры для загрузки кода из другого места или применения к нему предварительной обработки.
Пользовательские импортеры реализуются в два отдельных этапа. Finder отвечает за обнаружение модуля и предоставляет загрузчик для управления фактическим импортом. Пользовательские средства поиска модулей добавляются путем добавления фабрики в список sys.path_hooks
. При импорте каждая часть пути передается искателю до тех пор, пока один из них не заявит о поддержке (не вызывая ImportError
). Затем этот искатель отвечает за поиск в хранилище данных, представленном его записью пути, для именованных модулей.
sys_path_hooks_noisy.py
import sys class NoisyImportFinder: PATH_TRIGGER 'NoisyImportFinder_PATH_TRIGGER' def __init__(self, path_entry): print('Checking {}:'.format(path_entry), end' ') if path_entry self.PATH_TRIGGER: print('wrong finder') raise ImportError() else: print('works') return def find_module(self, fullname, pathNone): print('Looking for {!r}'.format(fullname)) return None sys.path_hooks.append(NoisyImportFinder) for hook in sys.path_hooks: print('Path hook: {}'.format(hook)) sys.path.insert(0, NoisyImportFinder.PATH_TRIGGER) try: print('importing target_module') import target_module except Exception as e: print('Import failed:', e)
Этот пример показывает, как создаются и запрашиваются средства поиска. NoisyImportFinder
вызывает ImportError
при создании экземпляра с записью пути, которая не соответствует его специальному значению триггера, которое, очевидно, не является реальным путем в файловой системе. Этот тест не позволяет NoisyImportFinder
нарушать импорт реальных модулей.
$ python3 sys_path_hooks_noisy.py Path hook:Path hook: .path_hook_for_FileFinder at 0x101afb6a8> Path hook: importing target_module Checking NoisyImportFinder_PATH_TRIGGER: works Looking for 'target_module' Import failed: No module named 'target_module'
Импорт с полки
Когда средство поиска обнаруживает модуль, оно отвечает за возврат загрузчика , способного импортировать этот модуль. В этом примере показан настраиваемый импортер, который сохраняет содержимое своего модуля в базе данных, созданной с помощью shelve.
Сначала используется сценарий для заполнения полки пакетом, содержащим субмодуль и субпакет.
sys_shelve_importer_create.py
import shelve import os filename '/tmp/pymotw_import_example.shelve' if os.path.exists(filename + '.db'): os.unlink(filename + '.db') with shelve.open(filename) as db: db['data:README'] b""" package README This is the README for ``package``. """ db['package.__init__'] b""" print('package imported') message = 'This message is in package.__init__' """ db['package.module1'] b""" print('package.module1 imported') message = 'This message is in package.module1' """ db['package.subpackage.__init__'] b""" print('package.subpackage imported') message = 'This message is in package.subpackage.__init__' """ db['package.subpackage.module2'] b""" print('package.subpackage.module2 imported') message = 'This message is in package.subpackage.module2' """ db['package.with_error'] b""" print('package.with_error being imported') raise ValueError('raising exception to break import') """ print('Created {} with:'.format(filename)) for key in sorted(db.keys()): print(' ', key)
Настоящий сценарий упаковки будет читать содержимое из файловой системы, но для такого простого примера, как этот, достаточно использовать жестко заданные значения.
$ python3 sys_shelve_importer_create.py Created /tmp/pymotw_import_example.shelve with: data:README package.__init__ package.module1 package.subpackage.__init__ package.subpackage.module2 package.with_error
Пользовательский импортер должен предоставить классы поиска и загрузчика, которые знают, как искать на полке источник модуля или пакета.
sys_shelve_importer.py
import imp import os import shelve import sys def _mk_init_name(fullname): """Return the name of the __init__ module for a given package name. """ if fullname.endswith('.__init__'): return fullname return fullname + '.__init__' def _get_key_name(fullname, db): """Look in an open shelf for fullname or fullname.__init__, return the name found. """ if fullname in db: return fullname init_name _mk_init_name(fullname) if init_name in db: return init_name return None class ShelveFinder: """Find modules collected in a shelve archive.""" _maybe_recursing False def __init__(self, path_entry): # Loading shelve causes an import recursive loop when it # imports dbm, and we know we are not going to load the # module # being imported, so when we seem to be # recursing just ignore the request so another finder # will be used. if ShelveFinder._maybe_recursing: raise ImportError try: # Test the path_entry to see if it is a valid shelf try: ShelveFinder._maybe_recursing True with shelve.open(path_entry, 'r'): pass finally: ShelveFinder._maybe_recursing False except Exception as e: print('shelf could not import from {}: {}'.format( path_entry, e)) raise else: print('shelf added to import path:', path_entry) self.path_entry path_entry return def __str__(self): return '<{} for {!r}>'.format(self.__class__.__name__, self.path_entry) def find_module(self, fullname, pathNone): path path or self.path_entry print('\nlooking for {!r}\n in {}'.format( fullname, path)) with shelve.open(self.path_entry, 'r') as db: key_name _get_key_name(fullname, db) if key_name: print(' found it as {}'.format(key_name)) return ShelveLoader(path) print(' not found') return None class ShelveLoader: """Load source for modules from shelve databases.""" def __init__(self, path_entry): self.path_entry path_entry return def _get_filename(self, fullname): # Make up a fake filename that starts with the path entry # so pkgutil.get_data() works correctly. return os.path.join(self.path_entry, fullname) def get_source(self, fullname): print('loading source for {!r} from shelf'.format( fullname)) try: with shelve.open(self.path_entry, 'r') as db: key_name _get_key_name(fullname, db) if key_name: return db[key_name] raise ImportError( 'could not find source for {}'.format( fullname) ) except Exception as e: print('could not load source:', e) raise ImportError(str(e)) def get_code(self, fullname): source self.get_source(fullname) print('compiling code for {!r}'.format(fullname)) return compile(source, self._get_filename(fullname), 'exec', dont_inheritTrue) def get_data(self, path): print('looking for data\n in {}\n for {!r}'.format( self.path_entry, path)) if not path.startswith(self.path_entry): raise IOError path path[len(self.path_entry) + 1:] key_name 'data:' + path try: with shelve.open(self.path_entry, 'r') as db: return db[key_name] except Exception: # Convert all errors to IOError raise IOError() def is_package(self, fullname): init_name _mk_init_name(fullname) with shelve.open(self.path_entry, 'r') as db: return init_name in db def load_module(self, fullname): source self.get_source(fullname) if fullname in sys.modules: print('reusing module from import of {!r}'.format( fullname)) mod sys.modules[fullname] else: print('creating a new module object for {!r}'.format( fullname)) mod sys.modules.setdefault( fullname, imp.new_module(fullname) ) # Set a few properties required by PEP 302 mod.__file__ self._get_filename(fullname) mod.__name__ fullname mod.__path__ self.path_entry mod.__loader__ self # PEP-366 specifies that package's set __package__ to # their name, and modules have it set to their parent # package (if any). if self.is_package(fullname): mod.__package__ fullname else: mod.__package__ '.'.join(fullname.split('.')[:-1]) if self.is_package(fullname): print('adding path for package') # Set __path__ for packages # so we can find the sub-modules. mod.__path__ [self.path_entry] else: print('imported as regular module') print('execing source...') exec(source, mod.__dict__) print('done') return mod
Теперь ShelveFinder
и ShelveLoader
можно использовать для импорта кода с полки. Например, импорт только что созданного пакета
:
sys_shelve_importer_package.py
import sys import sys_shelve_importer def show_module_details(module): print(' message :', module.message) print(' __name__ :', module.__name__) print(' __package__:', module.__package__) print(' __file__ :', module.__file__) print(' __path__ :', module.__path__) print(' __loader__ :', module.__loader__) filename '/tmp/pymotw_import_example.shelve' sys.path_hooks.append(sys_shelve_importer.ShelveFinder) sys.path.insert(0, filename) print('Import of "package":') import package print() print('Examine package details:') show_module_details(package) print() print('Global settings:') print('sys.modules entry:') print(sys.modules['package'])
Полка добавляется к пути импорта при первом импорте после изменения пути. Средство поиска распознает полку и возвращает загрузчик, который используется для всего импорта с этой полки. Первоначальный импорт на уровне пакета создает новый объект модуля, а затем использует exec
для запуска источника, загруженного с полки. Он использует новый модуль в качестве пространства имен, так что имена, определенные в источнике, сохраняются как атрибуты уровня модуля.
$ python3 sys_shelve_importer_package.py Import of "package": shelf added to import path: /tmp/pymotw_import_example.shelve looking for 'package' in /tmp/pymotw_import_example.shelve found it as package.__init__ loading source for 'package' from shelf creating a new module object for 'package' adding path for package execing source... package imported done Examine package details: message : This message is in package.__init__ __name__ : package __package__: package __file__ : /tmp/pymotw_import_example.shelve/package __path__ : ['/tmp/pymotw_import_example.shelve'] __loader__ :Global settings: sys.modules entry: )>
Импорт пользовательского пакета
Таким же образом происходит загрузка других модулей и подпакетов.
sys_shelve_importer_module.py
import sys import sys_shelve_importer def show_module_details(module): print(' message :', module.message) print(' __name__ :', module.__name__) print(' __package__:', module.__package__) print(' __file__ :', module.__file__) print(' __path__ :', module.__path__) print(' __loader__ :', module.__loader__) filename '/tmp/pymotw_import_example.shelve' sys.path_hooks.append(sys_shelve_importer.ShelveFinder) sys.path.insert(0, filename) print('Import of "package.module1":') import package.module1 print() print('Examine package.module1 details:') show_module_details(package.module1) print() print('Import of "package.subpackage.module2":') import package.subpackage.module2 print() print('Examine package.subpackage.module2 details:') show_module_details(package.subpackage.module2)
Средство поиска получает полное имя загружаемого модуля, разделенное точками, и возвращает ShelveLoader
, настроенный для загрузки модулей из записи пути, указывающей на файл полки. Полное имя модуля передается в метод загрузчика load_module ()
, который создает и возвращает экземпляр module
.
$ python3 sys_shelve_importer_module.py Import of "package.module1": shelf added to import path: /tmp/pymotw_import_example.shelve looking for 'package' in /tmp/pymotw_import_example.shelve found it as package.__init__ loading source for 'package' from shelf creating a new module object for 'package' adding path for package execing source... package imported done looking for 'package.module1' in /tmp/pymotw_import_example.shelve found it as package.module1 loading source for 'package.module1' from shelf creating a new module object for 'package.module1' imported as regular module execing source... package.module1 imported done Examine package.module1 details: message : This message is in package.module1 __name__ : package.module1 __package__: package __file__ : /tmp/pymotw_import_example.shelve/package.module1 __path__ : /tmp/pymotw_import_example.shelve __loader__ :Import of "package.subpackage.module2": looking for 'package.subpackage' in /tmp/pymotw_import_example.shelve found it as package.subpackage.__init__ loading source for 'package.subpackage' from shelf creating a new module object for 'package.subpackage' adding path for package execing source... package.subpackage imported done looking for 'package.subpackage.module2' in /tmp/pymotw_import_example.shelve found it as package.subpackage.module2 loading source for 'package.subpackage.module2' from shelf creating a new module object for 'package.subpackage.module2' imported as regular module execing source... package.subpackage.module2 imported done Examine package.subpackage.module2 details: message : This message is in package.subpackage.module2 __name__ : package.subpackage.module2 __package__: package.subpackage __file__ : /tmp/pymotw_import_example.shelve/package.subpackage.module2 __path__ : /tmp/pymotw_import_example.shelve __loader__ :
Перезагрузка модулей в пользовательском импортере
Перезагрузка модуля осуществляется немного иначе. Вместо создания нового объекта модуля повторно используется существующий объект.
sys_shelve_importer_reload.py
import importlib import sys import sys_shelve_importer filename '/tmp/pymotw_import_example.shelve' sys.path_hooks.append(sys_shelve_importer.ShelveFinder) sys.path.insert(0, filename) print('First import of "package":') import package print() print('Reloading "package":') importlib.reload(package)
При повторном использовании того же объекта существующие ссылки на модуль сохраняются, даже если определения класса или функции изменяются при перезагрузке.
$ python3 sys_shelve_importer_reload.py First import of "package": shelf added to import path: /tmp/pymotw_import_example.shelve looking for 'package' in /tmp/pymotw_import_example.shelve found it as package.__init__ loading source for 'package' from shelf creating a new module object for 'package' adding path for package execing source... package imported done Reloading "package": looking for 'package' in /tmp/pymotw_import_example.shelve found it as package.__init__ loading source for 'package' from shelf reusing module from import of 'package' adding path for package execing source... package imported done
Обработка ошибок импорта
Если модуль не может быть обнаружен никаким средством поиска, ImportError
вызывается основным кодом импорта.
sys_shelve_importer_missing.py
import sys import sys_shelve_importer filename '/tmp/pymotw_import_example.shelve' sys.path_hooks.append(sys_shelve_importer.ShelveFinder) sys.path.insert(0, filename) try: import package.module3 except ImportError as e: print('Failed to import:', e)
Распространяются другие ошибки при импорте.
$ python3 sys_shelve_importer_missing.py shelf added to import path: /tmp/pymotw_import_example.shelve looking for 'package' in /tmp/pymotw_import_example.shelve found it as package.__init__ loading source for 'package' from shelf creating a new module object for 'package' adding path for package execing source... package imported done looking for 'package.module3' in /tmp/pymotw_import_example.shelve not found Failed to import: No module named 'package.module3'
Данные пакета
В дополнение к определению API для загрузки исполняемого кода Python, PEP 302 определяет дополнительный API для извлечения данных пакета, предназначенных для распространения файлов данных, документации и других ресурсов, не связанных с кодом, используемых пакетом. Реализуя get_data ()
, загрузчик может позволить вызывающим приложениям поддерживать получение данных, связанных с пакетом, без учета того, как пакет фактически установлен (особенно без предположения, что пакет хранится как файлы в файле. система).
sys_shelve_importer_get_data.py
import sys import sys_shelve_importer import os import pkgutil filename '/tmp/pymotw_import_example.shelve' sys.path_hooks.append(sys_shelve_importer.ShelveFinder) sys.path.insert(0, filename) import package readme_path os.path.join(package.__path__[0], 'README') readme pkgutil.get_data('package', 'README') # Equivalent to: # readme = package.__loader__.get_data(readme_path) print(readme.decode('utf-8')) foo_path os.path.join(package.__path__[0], 'foo') try: foo pkgutil.get_data('package', 'foo') # Equivalent to: # foo = package.__loader__.get_data(foo_path) except IOError as err: print('ERROR: Could not load "foo"', err) else: print(foo)
get_data ()
принимает путь на основе модуля или пакета, который владеет данными, и возвращает содержимое “файла” ресурса в виде байтовой строки или вызывает IOError
, если ресурс не существует.
$ python3 sys_shelve_importer_get_data.py shelf added to import path: /tmp/pymotw_import_example.shelve looking for 'package' in /tmp/pymotw_import_example.shelve found it as package.__init__ loading source for 'package' from shelf creating a new module object for 'package' adding path for package execing source... package imported done looking for data in /tmp/pymotw_import_example.shelve for '/tmp/pymotw_import_example.shelve/README' package README This is the README for ``package``. looking for data in /tmp/pymotw_import_example.shelve for '/tmp/pymotw_import_example.shelve/foo' ERROR: Could not load "foo"
Смотрите также
- pkgutil – включает
get_data ()
для получения данных из пакета.
Кэш импортера
Поиск по всем перехватчикам каждый раз при импорте модуля может стать дорогостоящим. Для экономии времени sys.path_importer_cache
поддерживается как отображение между записью пути и загрузчиком, который может использовать это значение для поиска модулей.
sys_path_importer_cache.py
import os import sys prefix os.path.abspath(sys.prefix) print('PATH:') for name in sys.path: name name.replace(prefix, '...') print(' ', name) print() print('IMPORTERS:') for name, cache_value in sys.path_importer_cache.items(): if '..' in name: name os.path.abspath(name) name name.replace(prefix, '...') print(' {}: {!r}'.format(name, cache_value))
FileFinder
используется для расположения путей, найденных в файловой системе. Местоположения на пути, не поддерживаемые никаким средством поиска, связаны с None
, поскольку они не могут использоваться для импорта модулей. Вывод ниже был усечен из-за ограничений форматирования.
$ python3 sys_path_importer_cache.py PATH: /Users/dhellmann/Documents/PyMOTW/Python3/pymotw-3/source/sys .../lib/python35.zip .../lib/python3.5 .../lib/python3.5/plat-darwin .../lib/python3.5/lib-dynload .../lib/python3.5/site-packages IMPORTERS: sys_path_importer_cache.py: None .../lib/python3.5/encodings: FileFinder( '.../lib/python3.5/encodings') .../lib/python3.5/lib-dynload: FileFinder( '.../lib/python3.5/lib-dynload') .../lib/python3.5/lib-dynload: FileFinder( '.../lib/python3.5/lib-dynload') .../lib/python3.5/site-packages: FileFinder( '.../lib/python3.5/site-packages') .../lib/python3.5: FileFinder( '.../lib/python3.5/') .../lib/python3.5/plat-darwin: FileFinder( '.../lib/python3.5/plat-darwin') .../lib/python3.5: FileFinder( '.../lib/python3.5') .../lib/python35.zip: None .../lib/python3.5/plat-darwin: FileFinder( '.../lib/python3.5/plat-darwin')
Мета Путь
sys.meta_path
дополнительно расширяет источники потенциального импорта, позволяя искать средство поиска перед сканированием обычного sys.path
. API для поисковика на мета-пути такой же, как и для обычного пути. Разница в том, что метаискатель не ограничен одной записью в sys.path
– он может искать где угодно.
sys_meta_path.py
import sys import types class NoisyMetaImportFinder: def __init__(self, prefix): print('Creating NoisyMetaImportFinder for {}'.format( prefix)) self.prefix prefix return def find_module(self, fullname, pathNone): print('looking for {!r} with path {!r}'.format( fullname, path)) name_parts fullname.split('.') if name_parts and name_parts[0] self.prefix: print(' ... found prefix, returning loader') return NoisyMetaImportLoader(path) else: print(' ... not the right prefix, cannot load') return None class NoisyMetaImportLoader: def __init__(self, path_entry): self.path_entry path_entry return def load_module(self, fullname): print('loading {}'.format(fullname)) if fullname in sys.modules: mod sys.modules[fullname] else: mod sys.modules.setdefault( fullname, types.ModuleType(fullname)) # Set a few properties required by PEP 302 mod.__file__ fullname mod.__name__ fullname # always looks like a package mod.__path__ ['path-entry-goes-here'] mod.__loader__ self mod.__package__ '.'.join(fullname.split('.')[:-1]) return mod # Install the meta-path finder sys.meta_path.append(NoisyMetaImportFinder('foo')) # Import some modules that are "found" by the meta-path finder print() import foo print() import foo.bar # Import a module that is not found print() try: import bar except ImportError as e: pass
Каждый искатель на мета-пути опрашивается перед поиском в sys.path
, поэтому всегда есть возможность иметь центральный импортер для загрузки модулей без явного изменения sys.path
. После того, как модуль «найден», API загрузчика работает так же, как и для обычных загрузчиков (хотя этот пример для простоты усечен).
$ python3 sys_meta_path.py Creating NoisyMetaImportFinder for foo looking for 'foo' with path None ... found prefix, returning loader loading foo looking for 'foo.bar' with path ['path-entry-goes-here'] ... found prefix, returning loader loading foo.bar looking for 'bar' with path None ... not the right prefix, cannot load
Смотрите также
- importlib – базовые классы и другие инструменты для создания пользовательских импортеров.
- zipimport – реализует импорт модулей Python из архивов ZIP.
- Внутренняя структура яиц Python – документация setuptools для формата яйца
- Wheel – документация для формата архива
wheel
для устанавливаемого кода Python. - PEP 302 – обработчики импорта
- PEP 366 – явный относительный импорт основного модуля
- PEP 427 – двоичный формат пакета Wheel 1.0
- Импортируйте это, это и Другое дело: пользовательские импортеры – презентация Бретта Кэннона на PyCon 2010.