Bir python paketinin parçası olan tüm modülleri listeleyin.


107

Bir python paketinin parçası olan tüm modülleri bulmanın basit bir yolu var mı? Gerçekten kesin olmayan bu eski tartışmayı buldum , ancak os.listdir () tabanlı kendi çözümümü sunmadan önce kesin bir cevaba sahip olmayı çok isterim.


6
@ S.Lott: Daha genel çözümler mevcuttur, python paketleri her zaman dosya sistemindeki dizinlerde bulunmaz, ancak ziplerin içinde de olabilir.
u0b34a0f6ae

4
neden tekerleği yeniden icat ettin? Python, Python 4, pkgutil'de hipermodüller alırsa ve bununla güncellenirse, kodum yine de çalışır. Mevcut soyutlamaları kullanmayı seviyorum. Sağlanan açık yöntemi kullanın, test edilir ve çalıştığı bilinir. Bunu yeniden uygulayarak .. şimdi her köşe davasını kendiniz bulmalı ve çalışmalısınız.
u0b34a0f6ae

1
@ S.Lott: Yani uygulama her başladığında, sadece bunu kontrol etmek için bir yumurta içine kurulursa kendi yumurtasını açacak mı? Bu işlevde tekerleği yeniden icat etmek için lütfen projeme karşı bir yama gönderin: git.gnome.org/cgit/kupfer/tree/kupfer/plugins.py#n17 . Lütfen hem yumurtaları hem de normal dizinleri dikkate alın, 20 satırı geçmeyin.
u0b34a0f6ae

1
@ S.Lott: Neden alakalı olduğunu anlamıyorsun anlayamadığın bir şey. Bunu programlı olarak keşfetmek, uygulamanın kullanıcıyla değil, bir paketin içeriğiyle ilgilenmesi ile ilgilidir.
u0b34a0f6ae

3
Tabii ki programlı olarak demek istiyorum! Aksi takdirde "kendi çözümümü os.listdir () ile kullanıma sunma"
demezdim

Yanıtlar:


145

Evet, buna dayalı pkgutilveya benzeri bir şey istiyorsunuz - bu şekilde, yumurta veya fermuarlı olup olmadıklarına bakılmaksızın tüm paketlere aynı şekilde davranabilirsiniz (burada os.listdir yardımcı olmaz).

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)

Bunları da nasıl içe aktarabilirim? __import__Normal olarak kullanabilirsiniz :

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
bu neyle importerdöndürülür pkgutil.iter_modules? Görünüşe göre "bilgisayar korsanlığı" yerine onu bir modülü içe aktarmak için kullanabilir miyim __import__(modname, fromlist="dummy")?
MestreLion

29
İthalatçıyı şu şekilde kullanabildim: m = importer.find_module(modname).load_module(modname)ve sonra mmodül, yani örneğin:m.myfunc()
chrisleague

@chrisleague ur metodunu python 2.7 ile kullanıyordum, ancak şimdi python 3.4 ile devam etmem gerekiyor, bu yüzden python 3 pkutil.iter_modules'te (module_loader, name, ispkg) yerine (module_finder, name, ispkg) verimi olduğunu biliyorsunuz. Önceki gibi çalışmasını sağlamak için ne yapabilirim?
crax

İlk örneğiniz şu hatayı veriyor : "AttributeError: 'module' nesnesinin özniteliği yok ' _path_ '" Bunun Python sürümüyle bir ilgisi var mı? (Python 2.7 kullanıyorum)
Apostolos

@Apostolos, yolun her iki tarafında yalnızca bir alt çizgi kullanıyorsunuz (yani _path_). Toplam dört (yani __path__) olmak üzere her iki tarafta iki tane olmalıdır .
therealmitchconnors

46

Bu iş için doğru araç pkgutil.walk_packages'dır.

Sisteminizdeki tüm modülleri listelemek için:

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

Walk_packages'ın tüm alt paketleri içe aktardığını, ancak alt modülleri almadığını unutmayın.

Belirli bir paketin tüm alt modüllerini listelemek isterseniz, bunun gibi bir şey kullanabilirsiniz:

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 yalnızca tek düzey derinlikteki modülleri listeler. walk_packages tüm alt modülleri alır. Scipy durumunda, örneğin, walk_packages şunu döndürür:

scipy.stats.stats

iter_modules yalnızca döndürürken

scipy.stats

Pkgutil ( http://docs.python.org/library/pkgutil.html ) üzerindeki dokümantasyon, /usr/lib/python2.6/pkgutil.py'de tanımlanan tüm ilginç işlevleri listelemiyor.

Belki de bu, işlevlerin "genel" arayüzün parçası olmadığı ve değişebileceği anlamına gelir.

Ancak, en azından Python 2.6'da (ve belki de daha önceki sürümlerde?) Pkgutil, mevcut tüm modülleri özyinelemeli olarak gezen bir walk_packages yöntemiyle birlikte gelir.



1
İkinci örneğiniz şu hatayı üretiyor: "AttributeError:" modül "nesnesinin" _path_ " özniteliği yok " - ' scipy ' ile test etmedim, ancak birkaç paketle . Bunun Python sürümüyle bir ilgisi var mı? (Python 2.7 kullanıyorum)
Apostolos

1
@Apostolos: _Önce ve sonra iki alt çizgi ( ) olmalıdır path- yani kullanmakpackage.__path__ yerine kullanınpackage._path_ . Kodu yeniden yazmak yerine kesip yapıştırmayı denemek daha kolay olabilir.
unutbu

Yorumu yazdığımda iki tane vardı! :) Ama sistem tarafından elimine edildi. Benim hatam; Üç alt çizgi koymalıydım. Ama o zaman italik kullanmak istersem sorun olmazdı, ki kullanmadım! ... Bu bir kayıp-kayıp durumu. :) Neyse, kodu çalıştırdığımda ikisini kullandım tabii ki. (Kodu kopyalayıp yapıştırdım.)
Apostolos

@Apostolos: Değişkenin packagebir modülü değil, bir paketi işaret ettiğinden emin olun . Modüller dosyalardır, paketler ise dizindir. Tüm paketler __path__özniteliğe sahiptir (... birisi herhangi bir nedenle özniteliği silmediyse.)
unutbu

2

Bu benim için çalışıyor:

import types

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

1
Bu iki şekilde başarısız olur 1. paketler alt modüllerini her zaman üst düzey ad alanına açıkça içe aktarmaz 2. paketler, diğer üçüncü taraf modülleri üst düzey ad alanlarına içe aktarabilir
wim

0

Paketimde canlı olarak düzenlediğim tüm alt modülleri yeniden yüklemenin bir yolunu arıyordum. Bu, yukarıdaki cevapların / yorumların bir kombinasyonudur, bu yüzden bunu bir yorum yerine burada bir cevap olarak göndermeye karar verdim.

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

İşte aklıma gelen tek yol:

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

Kesinlikle temizlenebilir ve geliştirilebilir.

DÜZENLEME: İşte biraz daha güzel bir sürüm:

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

NOT: Bu aynı zamanda, paketin bir alt dizininde bulunması gerekmeyen modülleri de bulacaktır, eğer __init__.pydosyasında çekilirlerse , yani bir paketin "parçası" derken neyi kastettiğinize bağlıdır.


üzgünüm, bunun bir faydası yok. Yanlış pozitiflerin yanı sıra, yalnızca zaten ithal edilmiş paket alt modülleri de bulacaktır.
u0b34a0f6ae
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.