如何确定模块名称是否属于Python标准库

14

我有一个模块的名字,是以字符串形式给定的(例如'logging'),这是通过查询对象的“module”属性得到的。

我如何区分属于我的项目和属于Python标准库的模块?

我知道我可以使用pip.get_installed_distributions()检查是否安装了此模块,但这些与标准库无关。

注意:我正在使用Python 2.7,因此仅在Python 3.x中适用的解决方案不太相关。

这里的答案不同,我正在寻找一种可以在O(1)时间内运行且不需要保存结果数组或为每个查询扫描目录的解决方案。

谢谢。


1
可能是重复的问题:如何获取所有Python标准库模块的列表 - Alperen
1
我很好奇你为什么想这样做,以防有其他解决方法可以实现你想做的事情。 - Stephen Paulger
通常情况下,您不希望这样做。例如,当代码库将由不同的Python版本运行时,某些模块可能会在原始库和第三方/后移库之间移动。如果您的问题是导入语法不明确,则应使其明确,例如通过完全限定模块或使用相对导入。 - ivan_pozdeev
同时查看重复的内容,使用isort的这个答案可能更好,至少对我来说,我已经安装了它,而不是stdlib_list。https://dev59.com/aGw15IYBdhLWcg3wqNqM#21659703 - CodeMonkey
4个回答

5

编辑:

我使用了这个解决方案(source)。

import distutils.sysconfig as sysconfig
import os

def std_modules():
    ret_list = []
    std_lib = sysconfig.get_python_lib(standard_lib=True)
    for top, dirs, files in os.walk(std_lib):
        for nm in files:
            if nm != '__init__.py' and nm[-3:] == '.py':
                ret_list.append(os.path.join(top, nm)[len(std_lib)+1:-3].replace('\\','.'))
    return ret_list
            
l = std_modules()
print("logging" in l)
print("os" in l)

输出:

False
True

这在Python 2和Python 3中都可以工作。 编辑之前: 我猜,你可以使用Python文档。 这里是 Python 2文档 Python 3文档的标准库部分。 此外,您可以选择精确的Python版本。

我需要一种能够实时工作的方法。我可以基于这个列表保存一个离线列表,但它需要进行非平凡的更新。 - Yohai Devir
@YohaiDe 好的,请试试这个。 - Alperen

4

使用标准模块imp的快速且简单的解决方案:

import imp
import os.path
import sys

python_path = os.path.dirname(sys.executable)

my_mod_name = 'logging'

module_path = imp.find_module(my_mod_name)[1]
if 'site-packages' in module_path or python_path in module_path or not imp.is_builtin(my_mod_name):
    print('module', my_mod_name, 'is not included in standard python library')

1
作为它失败的方式之一,它将无法检测从脚本目录导入的模块。 "快速而肮脏" 是一个恰当的描述。 - user2357112
1
我知道,“快速而不精确”是有原因的;)我添加了一个细化来包括在Python安装文件夹之外导入的模块。 - Guillaume
@user2357112,你有其他的失败示例吗?Guillaume的更新似乎解决了这个问题。 - Yohai Devir
@YohaiDe:这个更新修复了那个问题,但是对于像 sysitertools 这样的 C 模块却出现了问题。 - user2357112
1
C内置模块的修复 - Guillaume

2

这篇文章的旧版本也有一份好的答案:https://dev59.com/aGw15IYBdhLWcg3wqNqM#28873415

以下是操作步骤(首先需要执行pip install stdlib_list):

from stdlib_list import stdlib_list
import sys

all_stdlib_symbols = stdlib_list('.'.join([str(v) for v in sys.version_info[0:2]]))

module_name = 'collections'

if module_name in all_stdlib_symbols:
    print("%s is in stdlib" % module_name)

你需要先执行 pip install stdlib_list - shellcat_zero
确实感谢@shellcat_zero,我已经相应地更新了帖子。 - smarie

2

以上的解决方案都不是我想要的,所以我用另一种方法实现了。在这里发布,以防对任何人有用。

import os

def standard_lib_names_gen(include_underscored=False):
    standard_lib_dir = os.path.dirname(os.__file__)
    for filename in os.listdir(standard_lib_dir):
        if not include_underscored and filename.startswith('_'):
            continue
        filepath = os.path.join(standard_lib_dir, filename)
        name, ext = os.path.splitext(filename)
        if filename.endswith('.py') and os.path.isfile(filepath):
            if str.isidentifier(name):
                yield name
        elif os.path.isdir(filepath) and '__init__.py' in os.listdir(filepath):
            yield name

>>> standard_lib_names = set(standard_lib_names_gen(include_underscored=True))
>>> # verify that a few known libs are there (including three folders and three py files)
>>> assert {'collections', 'asyncio', 'os', 'dis', '__future__'}.issubset(standard_lib_names)
>>> # verify that other decoys are not in there
>>> assert {'__pycache__', 'LICENSE.txt', 'config-3.8-darwin', '.DS_Store'}.isdisjoint(standard_lib_names)
>>>
>>> len(standard_lib_names)
200
>>>
>>> # not including underscored
>>> standard_lib_names = set(standard_lib_names_gen(include_underscored=False))
>>> len(standard_lib_names)
184

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接