2009-01-28 67 views
69

是否有直接的方式列出包中所有模块的名称,而不使用__all__有没有一种标准的方式来列出包中的Python模块名称?

例如,假设这个包:

/testpkg 
/testpkg/__init__.py 
/testpkg/modulea.py 
/testpkg/moduleb.py 

我不知道是否有做这样的一个标准或内置方式:

>>> package_contents("testpkg") 
['modulea', 'moduleb'] 

手动的方法是遍历模块搜索路径以查找程序包的目录。然后可以列出该目录中的所有文件,过滤出唯一命名的py/pyc/pyo文件,剥离扩展名并返回该列表。但是对于模块导入机制已经在内部进行的操作来说,这似乎是相当多的工作。该功能暴露在任何地方?

回答

16

也许这将做你想要的?

import imp 
import os 
MODULE_EXTENSIONS = ('.py', '.pyc', '.pyo') 

def package_contents(package_name): 
    file, pathname, description = imp.find_module(package_name) 
    if file: 
     raise ImportError('Not a package: %r', package_name) 
    # Use a set because some may be both source and compiled. 
    return set([os.path.splitext(module)[0] 
     for module in os.listdir(pathname) 
     if module.endswith(MODULE_EXTENSIONS)]) 
-1

打印目录(模块)

+1

列出内容o f已经导入的模块。我正在寻找一种方法来列出尚未导入的包的内容,就像'from x import *'在未指定__all__时所做的一样。 – DNS 2009-01-28 15:16:52

+0

from x import *首先导入模块,然后将所有内容复制到当前模块。 – Seb 2009-01-28 15:29:17

+0

由于Windows上的区分大小写问题,我意识到'从x导入*'实际上并不导入包的子模块。我只是把它作为我想要做的一个例子,为了避免混淆,我编辑了它。 – DNS 2009-01-28 15:56:35

18
​​
+1

虽然帮助列出了帮助文本底部的软件包内容,但问题更多的是如何执行此操作:f(package_name)=> [“module1_name”,“module2_name”]。我想我可以解析帮助返回的字符串,但这似乎比列出目录更迂回。 – DNS 2009-01-28 21:56:44

+0

@DNS:`help()`输出东西,它不返回字符串。 – Junuxx 2013-01-15 14:45:48

-2
def package_contents(package_name): 
    package = __import__(package_name) 
    return [module_name for module_name in dir(package) if not module_name.startswith("__")] 
155

使用python2.3 and above,你也可以使用pkgutil模块:

>>> import pkgutil 
>>> [name for _, name, _ in pkgutil.iter_modules(['testpkg'])] 
['modulea', 'moduleb'] 

编辑:注意这个参数是不是一个模块列表,但路径列表,所以你可能想这样做:

>>> import os.path, pkgutil 
>>> import testpkg 
>>> pkgpath = os.path.dirname(testpkg.__file__) 
>>> print [name for _, name, _ in pkgutil.iter_modules([pkgpath])] 
6

不知道我是否忽略了某些东西,或者答案只是过时而已;

正如user815423426所述,这仅适用于活动对象,列出的模块只是之前导入的模块。

清单包模块似乎很容易使用inspect

>>> import inspect, testpkg 
>>> inspect.getmembers(testpkg, inspect.ismodule) 
['modulea', 'moduleb'] 
0

基于cdleary的例子,这里是所有子模块的递归版本上市路径:

import imp, os 

def iter_submodules(package): 
    file, pathname, description = imp.find_module('isc_datasources') 
    for dirpath, _, filenames in os.walk(pathname): 
     for filename in filenames: 
      if os.path.splitext(filename)[1] == ".py": 
       yield os.path.join(dirpath, filename) 
1

这是一个递归版本适用于python 3.6及以上版本:

import importlib.util 
from pathlib import Path 
import os 
MODULE_EXTENSIONS = '.py' 

def package_contents(package_name): 
    spec = importlib.util.find_spec(package_name) 
    if spec is None: 
     return set() 

    pathname = Path(spec.origin).parent 
    ret = set() 
    with os.scandir(pathname) as entries: 
     for entry in entries: 
      if entry.name.startswith('__'): 
       continue 
      current = '.'.join((package_name, entry.name.partition('.')[0])) 
      if entry.is_file(): 
       if entry.name.endswith(MODULE_EXTENSIONS): 
        ret.add(current) 
      elif entry.is_dir(): 
       ret.add(current) 
       ret |= package_contents(current) 


    return ret 
相关问题