Определение того, является ли данный модуль Python встроенным модулем
Я занимаюсь анализом и интроспекцией различных модулей, но я не хочу разбирать встроенные модули. Теперь нет специальных типов для встроенных модулей, таких как types.BuiltinFunctionType
, поэтому как это сделать?
>>> import CornedBeef
>>> CornedBeef
<module 'CornedBeef' from '/meatish/CornedBeef.pyc'>
>>> CornedBeef.__file__
'/meatish/CornedBeef.pyc'
>>> del CornedBeef.__file__
>>> CornedBeef
<module 'CornedBeef' (built-in)>
Согласно Python, модуль, по-видимому, встроен, если у него нет атрибута __file__
. Означает ли это, что hasattr(SomeModule, '__file__')
- это способ проверить, встроен ли модуль? Несомненно, это не совсем обычное явление для del SomeModule.__file__
, но есть ли более надежный способ определить, встроен ли модуль?
Ответы
Ответ 1
Кортеж строк с именами все модули, которые скомпилированы в этот интерпретатор Python. (Эта информация недоступна ни в одном other way - modules.keys() только списки импортированные модули.)
Ответ 2
Вы можете использовать imp.is_builtin
, чтобы узнать, соответствует ли имя модуля встроенному модулю, но я не могу думать о том, чтобы действительно надежно проверить объект модуля.
Вы также можете попробовать следующее:
>>> import imp
>>> f, path, desc = imp.find_module("sys")
>>> desc
('', '', 6)
>>> desc[2] == imp.C_BUILTIN
True
Ответ 3
Когда вы говорите "встроенный", вы имеете в виду, написанный на C, или вы имеете в виду часть стандартной библиотеки? Если вы имеете в виду первое, то поиск __file__
- это правильная вещь. Как вы можете видеть, даже интерпретатор Python использует наличие __file__
в качестве индикатора встроенного языка.
Если вы имеете в виду "часть стандартной библиотеки", то это очень сложно определить.
Ответ 4
Если вы считаете это просто, как задано, builtins
, то принятый ответ, очевидно, правильный.
В моем случае я искал также стандартную библиотеку, под которой я подразумеваю список всех импортируемых модулей, поставляемых с данным дистрибутивом Python. Вопросы об этом были заданы несколько раз, но я не мог найти ответ, который включал все, что я искал.
Мой пример использования заключался в том, что в выражении import x
Python import x
выполнялся произвольный x
:
- входящий в состав встроенных модулей Python stdlib +
- установлен как сторонний модуль
- ни
Это будет работать для virtualenvs или глобальной установки. Он запрашивает распределение всех двоичных файлов python с помощью script. Заключительный кусок действительно выходит из виртуального, но я считаю, что желаемое поведение.
# You may need to use setuptools.distutils depending on Python distribution.
import distutils
import glob
import os
import pkgutil
import sys
def get_python_library():
# Get list of the loaded source modules on sys.path.
modules = {
module
for _, module, package in list(pkgutil.iter_modules())
if package is False
}
# Glob all the 'top_level.txt' files installed under site-packages.
site_packages = glob.iglob(os.path.join(os.path.dirname(os.__file__)
+ '/site-packages', '*-info', 'top_level.txt'))
# Read the files for the import names and remove them from the modules list.
modules -= {open(txt).read().strip() for txt in site_packages}
# Get the system packages.
system_modules = set(sys.builtin_module_names)
# Get the just the top-level packages from the python install.
python_root = distutils.sysconfig.get_python_lib(standard_lib=True)
_, top_level_libs, _ = list(os.walk(python_root))[0]
return sorted(top_level_libs + list(modules | system_modules))
Возвращает
Сортированный список импорта: [..., 'imaplib', 'imghdr', 'imp', 'importlib', 'imputil', 'inspect', 'io', ...]
Объяснение
Я разбил его на куски, поэтому причина, по которой каждая группа нужна, может быть понятной.
-
modules
-
pkgutil.iter_modules
вызывает сканирование всех загруженных модулей на sys.path
и возвращает генератор кортежей (module_loader, name, ispkg)
.
- Я превращаю его в набор и отфильтровываю пакеты, так как здесь мы заботимся только об исходных модулях.
-
site_packages
- Получите список всех установленных пакетов в каталоге обычных пакетов сайтов и удалите их из списка
modules
. Это примерно соответствует третьим сторонам.
- Это была самая трудная часть, чтобы поправиться. Многие вещи почти сработали, например
pip.get_installed_distributions
или site
. Но pip
возвращает имена модулей, поскольку они находятся на PyPi, а не так, как они импортируются в исходный файл. Некоторые патологические пакеты проскальзывают через трещины, например:
-
requests-futures
, который импортируется как requests_futures
.
-
colors
, который на самом деле ansicolors
на PyPi и, таким образом, смешивает любую разумную эвристику.
- Я уверен, что есть некоторые модули с низким уровнем использования, которые не включают
top_level.txt
в свой пакет. Но это покрывало 100% моих случаев использования, похоже, работает над всем, что правильно настроено.
-
system_modules
- Если вы явно не запрашиваете их, вы не получите эти системные модули, например
sys
, gc
, errno
и некоторые другие дополнительные модули.
-
top_level_libs
-
distutils.sysconfig.get_python_lib(standard_lib=True)
возвращает каталог верхнего уровня независимой от платформы стандартной библиотеки.
- Их легко пропустить, потому что они могут не жить под одним и тем же путём, как и другие модули. Если вы находитесь на OSX и запускаете virtualenv, эти модули будут фактически импортированы из системы. Эти модули включают в себя
email
, logging
, xml
и еще несколько.
Заключение
Для моего MacBookPro 2013 года я нашел 403 модуля для установки python2.7
.
>>> print(sys.version)
2.7.10 (default, Jul 13 2015, 12:05:58)
[GCC 4.2.1 Compatible Apple LLVM 6.1.0 (clang-602.0.53)]
>>> print(sys.hexversion)
34015984
>>> python_stdlib = get_python_libirary()
>>> len(python_stdlib)
403
Я выставил текст код и вывод. Если вы считаете, что мне не хватает класса или включили фиктивный модуль, я хотел бы услышать об этом.
* Альтернативы
-
При написании этого сообщения я вырыл вокруг API pip
и setuptools
. Возможно, эта информация через один модуль, но вам действительно нужно знать свой путь вокруг этого API.
-
Прежде чем я начал это, мне сказали, что six
имеет функцию специально для этой проблемы. Это имеет смысл, что может существовать, но я не мог найти его сам.