Что предпочитает «импорт» - .pyd (.so) или .py? - PullRequest
6 голосов
/ 04 ноября 2019

У меня есть 2 файла в одном каталоге, файл скомпилированной библиотеки и исходный файл:

.
├── a.py
└── a.pyd

Похоже, import a, что фактически импортирует модуль a.pyd. Но я не могу найти какой-либо официальный документ, гарантирующий это.

Кто-нибудь знает о порядке импорта разных типов файлов?

Этот же вопрос относится к расширениям Unix Python (.so)

Ответы [ 2 ]

5 голосов
/ 04 ноября 2019

В типичной установке Python класс ExtensionFileLoader имеет приоритет над SourceFileLoader, который используется для файлов .py. Это ExtensionFileLoader, который обрабатывает импорт .pyd файлов, и на машине с Windows вы найдете .pyd, зарегистрированный в importlib.machinery.EXTENSION_SUFFIXES (примечание: в Linux / macOS он будет иметь .so ввместо этого).

Таким образом, в случае конфликта имен в одном и том же каталоге (что означает «связь» при просмотре sys.path по порядку), файл a.pyd имеет приоритет над файлом a.py,Вы можете убедиться, что при создании пустых файлов a.pyd и a.py оператор import a пытается загрузить DLL (и, конечно, не удается).

Чтобы увидеть приоритет в исходниках CPython, посмотрите здесь в importlib._bootstrap_external. _get_supported_file_loaders:

def _get_supported_file_loaders():
    """Returns a list of file-based module loaders.
    Each item is a tuple (loader, suffixes).
    """
    extensions = ExtensionFileLoader, _imp.extension_suffixes()
    source = SourceFileLoader, SOURCE_SUFFIXES
    bytecode = SourcelessFileLoader, BYTECODE_SUFFIXES
    return [extensions, source, bytecode]  # <-- extensions before source!

Ссылку на документ см. http://www.python.org/doc/essays/packages/

Что делать, если у меня есть модуль и пакетС тем же именем?

У вас может быть каталог (на sys.path), в котором есть как модуль spam.py, так и спам подкаталога, содержащий __init__.py (без __init__.py,каталог не распознается как пакет). В этом случае подкаталог имеет приоритет, и импорт спама будет игнорировать файл spam.py, загружая вместо этого спам пакета. Если вы хотите, чтобы модуль spam.py имел приоритет, он должен быть помещен в каталог, который находится ранее в sys.path.

(Совет: порядок поиска определяется списком суффиксов, возвращаемых функциейimp.get_suffixes (). Обычно суффиксы ищутся в следующем порядке: ".so", "module.so", ".py", ".pyc". Каталоги не появляются явно в этом списке, но предшествуют всемзаписей в нем.)

В этом документе явно не упоминается ".pyd", но это Windows-эквивалент ".so". Я только что проверил на компьютере с Windows, и действительно '.pyd' появляется перед '.py' в списке суффиксов.

Обратите внимание, что приведенная выше ссылка очень старая! Со времени написания этого эссе система импорта была полностью переработана, и основной механизм был открыт для пользователей (например, вы можете изменить sys.meta_path, чтобы зарегистрировать свои собственные загрузчики или изменить приоритет). Так что теперь можно было бы настроить «.py» так, чтобы он был предпочтительнее «.pyd», и не имеет большого значения, что imp.get_suffixes() говорит о чем-либо (на самом деле, эта функция устарела). Конечно, установка по умолчанию на Python этого не сделает, и приоритет по умолчанию останется таким же, как упомянуто выше.

0 голосов
/ 06 ноября 2019

Спасибо за ответ Вим.

import importlib
print(importlib.util.find_spec('a'))

показать результат

ModuleSpec(name='a', loader=<_frozen_importlib_external.ExtensionFileLoader object at 0x02A79EF0>, origin='a.pyd')

Хотя я не могу видеть порядок pyd, py.

По крайней мере, я могуразличайте, какой из них я импортирую в модульный.

...