Во-первых, я не думаю, что это вообще полезно. Модули очень часто являются оболочками на чистом Python для модуля расширения C или, в некоторых случаях, оболочками на чистом Python для модуля расширения C, если он доступен, или реализацией на чистом Python, если нет.
Некоторые популярные сторонние примеры: numpy
— это чистый Python, хотя все важное реализовано на C; bintrees
— это чистый Python, хотя все его классы могут быть реализованы либо на C, либо на Python, в зависимости от того, как вы его строите; и т.п.
И это верно для большинства стандартных библиотек, начиная с 3.2. Например, если вы просто import pickle
, классы реализации будут построены на C (то, что вы использовали, чтобы получить от cpickle
в 2.7) в CPython, в то время как они будут чисто версиями Python в PyPy, но в любом случае pickle
сам по себе является чистым Python .
Но если вы делаете это, вам нужно различать три вещи:
- Встроенные модули, такие как
sys
.
- Модули расширения C, такие как
cpickle
2.x.
- Чистые модули Python, такие как
pickle
2.x.
И это при условии, что вы заботитесь только о CPython; если ваш код работает, скажем, на Jython или IronPython, реализация может быть JVM или .NET, а не нативным кодом.
Вы не можете точно отличить на основе __file__
по ряду причин:
- У встроенных модулей вообще нет
__file__
. (Это задокументировано в нескольких местах, например, в таблице Типы и элементы. в документах inspect
.) Обратите внимание, что если вы используете что-то вроде py2app
или cx_freeze
, то, что считается «встроенным», может отличаться от автономной установки.
- Модуль чистого Python может иметь файл .pyc/.pyo без файла .py в распределенном приложении.
- Модуль в пакете, установленный как однофайловое яйцо (что характерно для
easy_install
, в меньшей степени для pip
), будет иметь либо пустой, либо бесполезный __file__
.
- Если вы создаете бинарный дистрибутив, есть большая вероятность, что вся ваша библиотека будет упакована в zip-файл, что вызовет ту же проблему, что и однофайловые яйца.
В версии 3.1+ процесс импорта был значительно очищен, в основном переписан на Python и в основном открыт для слоя Python.
Таким образом, вы можете использовать модуль importlib
, чтобы увидеть цепочку загрузчиков, используемых для загрузки module, и в конечном итоге вы получите BuiltinImporter
(встроенные модули), ExtensionFileLoader
(.so/.pyd/и т. д.), SourceFileLoader
(.py) или SourcelessFileLoader
(.pyc/.pyo).
Вы также можете увидеть суффиксы, назначенные каждому из четырех на текущей целевой платформе, как константы в importlib.machinery
. Таким образом, вы можете проверить, что any(pathname.endswith(suffix) for suffix in importlib.machinery.EXTENSION_SUFFIXES))
, но на самом деле это не поможет, например, в случае с яйцом/молнией, если только вы уже не продвинулись вверх по цепочке.
Лучшие эвристики, которые кто-либо придумал для этого, — это те, которые реализованы в модуле inspect
, поэтому лучше всего использовать их.
Лучшим выбором будет один или несколько из getsource
, getsourcefile
и getfile
; что лучше всего зависит от того, какую эвристику вы хотите.
Встроенный модуль поднимет TypeError
для любого из них.
Модуль расширения должен возвращать пустую строку для getsourcefile
. Кажется, это работает во всех версиях 2.5-3.4, которые у меня есть, но у меня нет 2.4. Для getsource
, по крайней мере, в некоторых версиях, он возвращает фактические байты файла .so, даже если он должен возвращать пустую строку или поднимать IOError
. (В 3.x вы почти наверняка получите UnicodeError
или SyntaxError
, но вы, вероятно, не хотите полагаться на это…)
Модули Pure Python могут возвращать пустую строку для getsourcefile
, если в файле egg/zip/etc. Они всегда должны возвращать непустую строку для getsource
, если исходный код доступен, даже внутри яйца/zip/и т. д., но если они представляют собой байт-код без исходного кода (.pyc/и т. д.), они вернут пустую строку или вызовут IOError .
Лучше всего поэкспериментировать с интересующей вас версией на интересующей вас платформе(ах) в дистрибутивах/настройках, которые вам интересны.
person
abarnert
schedule
02.12.2013
dir
/проверьте документы, чтобы узнать больше. - person Marcin   schedule 03.12.2013numpy
— это чистый модуль Python, аpickle
— это чистый Python, вне зависимости от того, получены ли_Pickle
и его друзья из ускорителя C или из чистого Python. - person abarnert   schedule 03.12.2013repr
, скажем,cPickle
в 2.7, у него есть путь, а не строкаbuilt-in
. И единственная официальная эвристика для различения встроенных модулей заключается в том, что отсутствует__file__
, что опять-таки неверно дляcPickle
. - person abarnert   schedule 03.12.2013__file__
модуля расширения заканчивается на.so
, когда используется реализация C, но я не знаю, всегда ли это так или обычно. - person cjerdonek   schedule 03.12.2013