Liệt kê tất cả các mô-đun là một phần của gói python?


107

Có cách nào đơn giản để tìm tất cả các mô-đun là một phần của gói python không? Tôi đã tìm thấy cuộc thảo luận cũ này , nó không thực sự kết luận, nhưng tôi muốn có câu trả lời chắc chắn trước khi tôi đưa ra giải pháp của riêng mình dựa trên os.listdir ().


6
@ S.Lott: Hiện có nhiều giải pháp tổng quát hơn, gói python không phải lúc nào cũng nằm trong thư mục trong hệ thống tệp, nhưng cũng có thể nằm bên trong khóa nén.
u0b34a0f6ae

4
tại sao lại phát minh ra bánh xe? Nếu python có được siêu mô-đun trong Python 4, pkgutil và được cập nhật với điều đó, mã của tôi sẽ vẫn hoạt động. Tôi thích sử dụng những thứ trừu tượng có sẵn. Sử dụng phương pháp rõ ràng được cung cấp, nó đã được thử nghiệm và được biết là hoạt động. Thực hiện lại điều đó .. bây giờ bạn phải tự tìm và làm việc xung quanh mọi trường hợp góc.
u0b34a0f6ae

1
@ S.Lott: Vì vậy, mỗi khi ứng dụng khởi động, nó sẽ giải nén quả trứng của chính nó nếu được cài đặt bên trong chỉ để kiểm tra điều này? Vui lòng gửi bản vá chống lại dự án của tôi để phát minh lại bánh xe trong chức năng này: git.gnome.org/cgit/kupfer/tree/kupfer/plugins.py#n17 . Vui lòng xem xét cả trứng và thư mục bình thường, không vượt quá 20 dòng.
u0b34a0f6ae

1
@ S.Lott: Tại sao bạn không hiểu rằng nó có liên quan là điều bạn không thể hiểu được. Khám phá điều này theo chương trình nghĩa là ứng dụng quan tâm đến nội dung của một gói chứ không phải người dùng.
u0b34a0f6ae

3
Tất nhiên ý tôi là có lập trình! Nếu không tôi sẽ không có đề cập đến "tung ra giải pháp của riêng tôi với os.listdir ()"
static_rtti

Câu trả lời:


145

Có, bạn muốn một cái gì đó dựa trên pkgutilhoặc tương tự - bằng cách này, bạn có thể coi tất cả các gói như nhau bất kể chúng nằm trong trứng hay khóa kéo hoặc tương tự (trong đó os.listdir sẽ không giúp được gì).

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)

Làm thế nào để nhập chúng quá? Bạn chỉ có thể sử dụng __import__như bình thường:

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
cái này được importertrả lại bằng pkgutil.iter_modulesgì? Tôi có thể sử dụng nó để nhập một mô-đun thay vì sử dụng có vẻ như "hackish" này __import__(modname, fromlist="dummy")không?
MestreLion

29
Tôi đã có thể sử dụng các nhà nhập khẩu như thế này: m = importer.find_module(modname).load_module(modname)và sau đó mlà mô-đun, vì vậy ví dụ:m.myfunc()
chrisleague

@chrisleague Tôi đang sử dụng phương thức ur với python 2.7, nhưng bây giờ tôi cần chuyển sang python 3.4, vì vậy bạn biết rằng trong python 3 pkutil.iter_modules cho kết quả (module_finder, name, ispkg) thay vì (module_loader, name, ispkg). Tôi có thể làm gì để làm cho nó hoạt động như trước đây?
crax

Ví dụ đầu tiên của bạn tạo ra lỗi sau: "AttributeError: Đối tượng 'module' không có thuộc tính ' _path_ '" Điều này có liên quan gì đến phiên bản Python không? (Tôi sử dụng Python 2.7)
Apostolos

@Apostolos, bạn chỉ đang sử dụng một dấu gạch dưới ở hai bên của đường dẫn (tức là _path_). Nên có hai ở hai bên, tổng cộng là bốn (tức là __path__).
therealmitchconnors

46

Công cụ phù hợp cho công việc này là pkgutil.walk_packages.

Để liệt kê tất cả các mô-đun trên hệ thống của bạn:

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

Lưu ý rằng walk_packages nhập tất cả các gói con, nhưng không nhập các mô-đun con.

Nếu bạn muốn liệt kê tất cả các mô-đun con của một gói nhất định thì bạn có thể sử dụng một cái gì đó như sau:

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 chỉ liệt kê các mô-đun sâu một cấp. walk_packages nhận tất cả các mô-đun con. Trong trường hợp scipy, ví dụ: walk_packages trả về

scipy.stats.stats

trong khi iter_modules chỉ trả về

scipy.stats

Tài liệu trên pkgutil ( http://docs.python.org/library/pkgutil.html ) không liệt kê tất cả các hàm thú vị được định nghĩa trong /usr/lib/python2.6/pkgutil.py.

Có lẽ điều này có nghĩa là các chức năng không phải là một phần của giao diện "công khai" và có thể thay đổi.

Tuy nhiên, ít nhất kể từ Python 2.6 (và có lẽ là các phiên bản trước đó?) Pkgutil đi kèm với phương thức walk_packages mà đệ quy duyệt qua tất cả các mô-đun có sẵn.


5
walk_packageshiện đang trong tài liệu hướng dẫn: docs.python.org/library/pkgutil.html#pkgutil.walk_packages
Cơ ốc

1
Ví dụ thứ hai của bạn tạo ra lỗi sau: "AttributeError: đối tượng 'module' không có thuộc tính ' _path_ '" - Tôi đã không kiểm tra nó với 'scipy' nhưng với một vài gói khác. Điều này có liên quan gì đến phiên bản Python không? (Tôi sử dụng Python 2.7)
Apostolos

1
@Apostolos: Nên có hai dấu gạch dưới ( _) trước và sau path- nghĩa là sử dụngpackage.__path__ hơn là package._path_. Có thể dễ dàng hơn để thử cắt và dán mã hơn là nhập lại.
unutbu

Có hai trong số họ, khi tôi viết bình luận! :) Nhưng chúng đã bị hệ thống tước bỏ. Lỗi của tôi; Tôi nên đặt ba lỗ gạch dưới. Nhưng sau đó, điều này sẽ ổn nếu tôi muốn sử dụng chữ in nghiêng, mà tôi đã không! ... Đó là một tình huống thua lỗ. :) Dù sao, khi tôi chạy mã, tất nhiên, tôi đã sử dụng hai trong số chúng. (Tôi đã sao chép-dán mã.)
Apostolos

@Apostolos: Đảm bảo rằng biến packageđang trỏ đến một gói chứ không phải một mô-đun. Mô-đun là tệp trong khi gói là thư mục. Tất cả các gói có __path__thuộc tính (... trừ khi ai đó xóa các thuộc tính đối với một số lý do.)
unutbu

2

Điều này phù hợp với tôi:

import types

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

1
Điều này không thành công theo hai cách 1. các gói không phải lúc nào cũng nhập rõ ràng các mô-đun con của chúng vào không gian tên cấp cao nhất 2. các gói có thể nhập các mô-đun của bên thứ 3 khác vào không gian tên cấp cao nhất của
chúng

0

Tôi đang tìm cách tải lại tất cả các mô-đun con mà tôi đang chỉnh sửa trực tiếp trong gói của mình. Nó là sự kết hợp của các câu trả lời / nhận xét ở trên, vì vậy tôi quyết định đăng nó ở đây như một câu trả lời hơn là một bình luận.

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

Đây là một cách, ngoài đầu tôi:

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

Nó chắc chắn có thể được làm sạch và cải thiện.

CHỈNH SỬA: Đây là một phiên bản đẹp hơn một chút:

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

LƯU Ý: Điều này cũng sẽ tìm thấy các mô-đun có thể không nhất thiết phải nằm trong thư mục con của gói, nếu chúng được kéo trong __init__.pytệp của nó , vì vậy nó phụ thuộc vào ý bạn muốn nói đến "một phần" của gói.


xin lỗi, điều đó không có ích. Ngoài kết quả dương tính giả, nó cũng sẽ chỉ tìm thấy các mô-đun con của các gói đã được nhập sẵn.
u0b34a0f6ae
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.