2009-01-28 45 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 
相關問題