首先,我认为这根本没有用。模块通常是围绕C扩展模块的纯Python包装,或者在某些情况下(如果有)围绕C扩展模块的纯Python包装,或者如果不存在,则是纯Python的实现。
对于一些流行的第三方示例:
numpy是纯Python,即使所有重要的事情都用C实现了;
bintrees是纯Python,即使其类可以全部用C或Python实现,具体取决于您如何构建它。等等
从3.2开始的大多数stdlib中都是如此。例如,如果您只是
importpickle,则实现类将
cpickle在CPython中用C构建(您以前从2.7中获取),而它们在PyPy中将是纯Python版本,但无论哪种方式,
pickle其本身都是纯Python。
但是,如果您 确实 想这样做,则实际上需要区分 三 件事:
- 内置模块,如
sys
。 - C扩展模块,例如2.x的
cpickle
。 - 纯Python模块,例如2.x的
pickle
。
假设您只关心CPython;如果您的代码在Jython或IronPython中运行,则实现可以是JVM或.NET,而不是本机代码。
__file__由于多种原因,您无法基于完美区分。
- 内置模块根本没有
__file__
。(在一些地方进行了记录(例如,文档中的Types和Members表inspect
)。)请注意,如果使用的是py2app
或cx_freeze
,则被视为“内置”的东西可能与独立安装的东西不同。 - 纯Python模块可能具有.pyc / .pyo文件,而分布式应用程序中没有.py文件。
- 安装为单文件egg的软件包中的模块(通常很常见
easy_install
,很少使用pip
)将是空白或无用__file__
。 - 如果构建二进制发行版,则很有可能将整个库打包到一个zip文件中,从而导致与单文件egg相同的问题。
在3.1及更高版本中,导入过程已被大量清理,大部分用Python重写,并且大部分暴露于Python层。
因此,您可以使用
importlib模块查看用于加载模块的加载程序链,最终您将获得
Builtinimporter(
ExtensionFileLoaderbuildins
),(。so / .pyd / etc。),
SourceFileLoader(。py )或
SourcelessFileLoader(.pyc
/.pyo)。
您还可以在当前目标平台上看到分配给这四个变量的后缀,作为中的常量
importlib.machinery。因此,您 可以
检查一下
any(pathname.endswith(suffix) for suffix inimportlib.machinery.EXTENSION_SUFFIXES)),但实际上并没有帮助,例如,除非您已经沿着链条向上旅行,否则在鸡蛋/拉链盒中也没有帮助。
任何人为此提出的最佳启发式方法都是在
inspect模块中实现的,因此最好的办法就是使用它。
最好的选择将是一个或多个
getsource,
getsourcefile和
getfile; 最好取决于您想要的启发式方法。
内置模块将为其中
TypeError任何一个引发一个。
扩展模块应为返回空字符串
getsourcefile。这似乎适用于我所有的2.5-3.4版本,但是我没有2.4版本。对于
getsource(至少在某些版本中),即使它应该返回一个空字符串或引发一个.so文件,它也将返回.so文件的实际字节
IOError。(在3.x中,您几乎肯定会得到
UnipreErroror
SyntaxError,但是您可能不想依赖它……)
getsourcefile如果在egg / zip /
etc中,纯Python模块可能会返回一个空字符串。
getsource如果源可用,即使在egg / zip /
etc等内部,它们也应始终返回非空字符串,但是,如果它们是无源字节码(.pyc / etc。),则它们将返回空字符串或引发IOError。
最好的选择是在您关心的发行版/安装程序中,在您关心的平台上试验您关心的版本。



