2009-11-10 16 views
70

C'è un modo semplice per trovare tutti i moduli che fanno parte di un pacchetto python? Ho trovato this old discussion, che non è davvero conclusivo, ma mi piacerebbe avere una risposta definitiva prima di distribuire la mia soluzione basata su os.listdir().Elenca tutti i moduli che fanno parte di un pacchetto python?

+0

Bonus: come si fa a importare i moduli trovati bene? –

+0

Cosa c'è di sbagliato leggendo la directory dei sorgenti? Di quali altre informazioni hai bisogno? Cosa c'è di sbagliato in 'ls' (o' dir')? –

+6

@ S.Lott: ci sono più soluzioni generali disponibili, i pacchetti python non sono sempre presenti nelle directory nel filesystem, ma possono anche trovarsi all'interno delle zip. – u0b34a0f6ae

risposta

100

Sì, si desidera qualcosa basato su pkgutil o simile - in questo modo è possibile trattare tutti i pacchetti uguali indipendentemente dal fatto che siano in egg o zip o così (dove os.listdir non aiuterà).

import pkgutil 

# this is the package we are inspecting -- for example 'email' from stdlib 
import email 

package = email 
for importer, modname, ispkg in pkgutil.iter_modules(package.__path__): 
    print "Found submodule %s (is a package: %s)" % (modname, ispkg) 

Come importarli anche loro? Si può solo usare __import__ come normale:

import pkgutil 

# this is the package we are inspecting -- for example 'email' from stdlib 
import email 

package = email 
prefix = package.__name__ + "." 
for importer, modname, ispkg in pkgutil.iter_modules(package.__path__, prefix): 
    print "Found submodule %s (is a package: %s)" % (modname, ispkg) 
    module = __import__(modname, fromlist="dummy") 
    print "Imported", module 
+6

cosa è questo 'importatore 'restituito da' pkgutil.iter_modules'? Posso usarlo per importare un modulo invece di usare questo apparentemente "hackish"? __import __ (modname, fromlist = "dummy") '? – MestreLion

+22

Sono stato in grado di utilizzare l'importatore in questo modo: 'm = importer.find_module (modname) .load_module (modname)' e quindi 'm' è il modulo, quindi ad esempio:' m.myfunc() ' – chrisleague

+0

@chrisleague I stavo usando il metodo ur con python 2.7, ma ora ho bisogno di andare avanti con python 3.4, quindi sai che in python 3 i rendimenti di pkutil.iter_modules (module_finder, name, ispkg) invece di (module_loader, name, ispkg). Cosa posso fare per farlo funzionare come il precedente? –

-2

Ecco un modo, la parte superiore della mia testa:

>>> import os 
>>> filter(lambda i: type(i) == type(os), [getattr(os, j) for j in dir(os)]) 
[<module 'UserDict' from '/usr/lib/python2.5/UserDict.pyc'>, <module 'copy_reg' from '/usr/lib/python2.5/copy_reg.pyc'>, <module 'errno' (built-in)>, <module 'posixpath' from '/usr/lib/python2.5/posixpath.pyc'>, <module 'sys' (built-in)>] 

Si potrebbe certamente essere ripulito e migliorato.

EDIT: Ecco una versione leggermente più bello:

>>> [m[1] for m in filter(lambda a: type(a[1]) == type(os), os.__dict__.items())] 
[<module 'copy_reg' from '/usr/lib/python2.5/copy_reg.pyc'>, <module 'UserDict' from '/usr/lib/python2.5/UserDict.pyc'>, <module 'posixpath' from '/usr/lib/python2.5/posixpath.pyc'>, <module 'errno' (built-in)>, <module 'sys' (built-in)>] 
>>> [m[0] for m in filter(lambda a: type(a[1]) == type(os), os.__dict__.items())] 
['_copy_reg', 'UserDict', 'path', 'errno', 'sys'] 

NOTA: Questo sarà anche trovare i moduli che potrebbero non necessariamente essere situati in una sottodirectory del pacchetto, se sono tirato in a il suo file __init__.py, quindi dipende da cosa intendi per "parte di" un pacchetto.

+0

scusa, che non ha senso. A parte i falsi positivi, troverà solo i sottomoduli già importati di pacchetti. – u0b34a0f6ae

30

Lo strumento giusto per questo lavoro è pkgutil.walk_packages.

per elencare tutti i moduli del sistema:

import pkgutil 
for importer, modname, ispkg in pkgutil.walk_packages(path=None, onerror=lambda x: None): 
    print(modname) 

essere consapevoli del fatto che le importazioni walk_packages tutti i pacchetti secondari, ma non sottomoduli.

Se si desidera elencare tutti i sottomoduli di un certo pacchetto, potete usare qualcosa di simile:

import pkgutil 
import scipy 
package=scipy 
for importer, modname, ispkg in pkgutil.walk_packages(path=package.__path__, 
                 prefix=package.__name__+'.', 
                 onerror=lambda x: None): 
    print(modname) 

iter_modules elenca solo i moduli che sono uno-livello profondo. walk_packages ottiene tutti i sottomoduli. Nel caso di SciPy, per esempio, walk_packages rendimenti

scipy.stats.stats 

mentre iter_modules restituisce solo

scipy.stats 

La documentazione sulla pkgutil (http://docs.python.org/library/pkgutil.html) non elenca tutte le funzioni interessanti definite in /usr /lib/python2.6/pkgutil.py.

Forse questo significa che le funzioni non fanno parte dell'interfaccia "pubblica" e sono soggette a modifiche.

Tuttavia, almeno a partire da Python 2.6 (e versioni precedenti, forse?) pkgutil viene fornito con un metodo walk_packages che cammina in modo ricorsivo attraverso tutte le moduli disponibili.

+4

'walk_packages' è ora nella documentazione: http://docs.python.org/library/pkgutil.html#pkgutil.walk_packages –

+0

Il tuo secondo esempio produce il seguente errore: **" AttributeError: ' modulo 'oggetto non ha attributo' __path __ '"** - Non l'ho provato con' scipy 'ma con pochi altri pacchetti. Ha qualcosa a che fare con la versione di Python? (Io uso Python 2.7) – Apostolos

+0

@Apostolos: Ci dovrebbero essere due caratteri di sottolineatura ('_') prima e dopo' path' - cioè, usare 'package .__ path__'] (https://stackoverflow.com/q/ 2699287/190597) anziché "pacchetto._punto_". Potrebbe essere più facile provare a tagliare e incollare il codice piuttosto che ridigitarlo. – unutbu

3

Questo funziona per me: domanda

import types 

for key, obj in nltk.__dict__.iteritems(): 
    if type(obj) is types.ModuleType: 
     print key 
Problemi correlati