Перерахуйте всі модулі, що входять до пакету python?


107

Чи є прямий спосіб знайти всі модулі, що входять до пакету python? Я знайшов цю стару дискусію , яка насправді не є переконливою, але я хотів би отримати певну відповідь, перш ніж розгорнути власне рішення на основі os.listdir ().


6
@ S.Lott: Є більш загальні рішення, пакети python не завжди знаходяться в каталогах файлової системи, але вони також можуть знаходитися всередині zip.
— u0b34a0f6ae

4
навіщо винаходити колесо? Якщо python придбає гіпермодулі в Python 4, pkgutil та оновиться з цим, мій код все одно буде працювати. Мені подобається використовувати доступні абстракції. Використовуйте очевидний метод, що надається, він перевірений і, як відомо, працює. Знову повторюючи це, тепер вам доведеться самостійно знаходити і вирішувати кожен кутовий випадок.
— u0b34a0f6ae

1
@ S.Lott: Отже, щоразу, коли програма запуститься, вона буде розпаковувати власне яйце, якщо воно встановлене всередині одного, щоб перевірити це? Будь ласка, надішліть виправлення проти мого проекту, щоб винаходити колесо у цій функції: git.gnome.org/cgit/kupfer/tree/kupfer/plugins.py#n17 . Зверніть увагу, як на яйця, так і на звичайні каталоги, не більше 20 рядків.
— u0b34a0f6ae

1
@ S.Lott: Чому ти не розумієш, що це актуально, це те, чого ти не можеш зрозуміти. Виявлення цього програмно полягає в тому, що додаток цікавить вміст пакету, а не користувача.
— u0b34a0f6ae

3
Звичайно, я маю на увазі програмно! Інакше я б не згадував про "розгортання власного рішення з os.listdir ()"
— static_rtti

Відповіді:


145

Так, ви хочете щось на основі pkgutilчи подібного - таким чином ви можете обробляти всі пакунки однаково, незалежно від того, чи є вони в яйцях чи блискавках чи так (де os.listdir не допоможе).

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)

Як їх імпортувати? Ви можете просто використовувати __import__як звичайне:

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

9
що це importerповертається pkgutil.iter_modules? Чи можу я використовувати його для імпорту модуля замість того, щоб використовувати цей, здавалося б, "хакічний" __import__(modname, fromlist="dummy")?
— MestreLion

29
Мені вдалося скористатись імпортером так: m = importer.find_module(modname).load_module(modname)а далі m- модуль, наприклад:m.myfunc()
— chrisleague

@chrisleague Я використовував метод ур з python 2.7, але тепер мені потрібно перейти до python 3.4, так що ви знаєте, що в python 3 pkutil.iter_modules виходить (module_finder, ім'я, ispkg) замість (module_loader, ім'я, ispkg). Що я можу зробити, щоб він працював як попередній?
— crax

Ваш перший приклад видає таку помилку: "AttributeError:" module "об'єкт не має атрибута" _path_ "" Це пов'язане з версією Python? (Я використовую Python 2.7)
— Апостолос

@Apostolos, ви використовуєте лише один підкреслення з обох боків шляху (тобто _path_). З обох боків повинно бути два (всього чотири __path__).
— therealmitchconnors

46

Правильним інструментом для цього завдання є pkgutil.walk_packages.

Щоб перерахувати всі модулі у вашій системі:

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

Майте на увазі, що walk_packages імпортує всі підпакети, але не підмодулі.

Якщо ви хочете перерахувати всі підмодулі певного пакету, ви можете використовувати щось подібне:

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 перелічує лише ті модулі, які є рівневими. walk_packages отримує всі підмодулі. Наприклад, у випадку з scipy, наприклад, walk_packages повертається

scipy.stats.stats

тоді як iter_modules лише повертається

scipy.stats

Документація на pkgutil ( http://docs.python.org/library/pkgutil.html ) не містить усіх цікавих функцій, визначених у /usr/lib/python2.6/pkgutil.py.

Можливо, це означає, що функції не є частиною "загальнодоступного" інтерфейсу і можуть змінюватися.

Однак, принаймні, як для Python 2.6 (а можливо, і більш ранніх версій?) Pkgutil поставляється з методом walk_packages, який рекурсивно проходить через всі наявні модулі.


5
walk_packagesтепер знаходиться в документації: docs.python.org/library/pkgutil.html#pkgutil.walk_packages
— Механічний равлик

1
У вашому другому прикладі виникає така помилка: "AttributeError:" модуль "об'єкта не має атрибута" _path_ "" - я не перевіряв його на "scipy", але з кількома іншими пакетами. Це щось пов’язане з версією Python? (Я використовую Python 2.7)
— Апостолос

1
@Apostolos: До _і після pathцього повинно бути дві підкреслення ( ) , тобто скоріше використовуватиpackage.__path__package._path_ . Можливо, буде простіше спробувати вирізати та вставити код, а не повторно вводити його.
— unutbu

Їх було двоє, коли я писав коментар! :) Але їх система позбавила. Моє ліжко; Я мав би поставити три підшерстя. Але тоді це було б добре, якби я хотів використовувати курсив, чого я не робив! ... Це ситуація з втратами. :) У всякому разі, коли я запускаю код, я, звичайно, використовував два. (Я копіюю-вставляю код.)
— Апостолос

@Apostolos: Переконайтеся, що змінна packageвказує на пакет, а не на модуль. Модулі - це файли, тоді як пакети - це каталоги. Усі пакети мають __path__атрибут (... якщо хтось не видалив атрибут з якоїсь причини.)
— unutbu

2

Це працює для мене:

import types

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

1
Це виходить з ладу двома способами 1. Пакети не завжди явно імпортують свої підмодулі в простір імен верхнього рівня 2. Пакети можуть імпортувати інші сторонні модулі у свій простір імен верхнього рівня
— wim

0

Я шукав спосіб перезавантажити всі підмодулі, які я редагую в прямому ефірі в своєму пакеті. Це поєднання вищевказаних відповідей / коментарів, тому я вирішив опублікувати це як відповідь, а не коментар.

package=yourPackageName
import importlib
import pkgutil
for importer, modname, ispkg in pkgutil.walk_packages(path=package.__path__, prefix=package.__name__+'.', onerror=lambda x: None):
    try:
        modulesource = importlib.import_module(modname)
        reload(modulesource)
        print("reloaded: {}".format(modname))
    except Exception as e:
        print('Could not load {} {}'.format(modname, e))

-4

Ось один із найголовніших завдань:

>>> 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)>]

Це, безумовно, можна було почистити та покращити.

EDIT: Ось трохи приємніша версія:

>>> [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']

ПРИМІТКА. У цьому випадку ви знайдете модулі, які не обов'язково будуть розташовані у підкаталозі пакету, якщо вони будуть введені у його __init__.pyфайл, тому це залежить від того, що ви маєте на увазі під "частиною" пакета.


вибачте, що не має користі. Крім помилкових позитивів, він також знайде лише імпортні підмодулі пакунків.
— u0b34a0f6ae
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.