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