파이썬 패키지의 일부인 모든 모듈을 나열 하시겠습니까?


107

파이썬 패키지의 일부인 모든 모듈을 찾는 간단한 방법이 있습니까? 나는 이 오래된 토론을 찾았 는데, 이것은 실제로 결정적이지는 않지만 os.listdir ()을 기반으로 한 내 자신의 솔루션을 출시하기 전에 확실한 답을 얻고 싶습니다.


6
@ S.Lott : 더 일반적인 솔루션을 사용할 수 있습니다. 파이썬 패키지는 항상 파일 시스템의 디렉토리에있는 것은 아니지만 zip 안에있을 수도 있습니다.
u0b34a0f6ae 2009

4
왜 바퀴를 재발 명합니까? 파이썬이 파이썬 4, pkgutil에서 하이퍼 모듈을 얻고 그로 업데이트하면 내 코드는 계속 작동합니다. 사용 가능한 추상화를 사용하고 싶습니다. 제공된 명백한 방법을 사용하십시오. 테스트를 거쳐 작동하는 것으로 알려져 있습니다. 다시 구현하면 .. 이제 모든 코너 케이스를 직접 찾아서 해결해야합니다.
u0b34a0f6ae

1
@ S.Lott : 그래서 응용 프로그램이 시작될 때마다, 단지 이것을 확인하기 위해 하나 안에 설치되면 자체 계란의 압축이 풀릴 것입니까? 이 함수에서 바퀴를 재발 명하기 위해 내 프로젝트에 대한 패치를 제출하십시오 : git.gnome.org/cgit/kupfer/tree/kupfer/plugins.py#n17 . 계란과 일반 디렉토리를 모두 고려하십시오. 20 줄을 초과하지 마십시오.
u0b34a0f6ae 2009

1
@ S.Lott : 왜 관련성이 있다는 것을 이해하지 못하는 이유는 이해할 수없는 것입니다. 이를 프로그래밍 방식으로 발견하는 것은 애플리케이션 이 사용자가 아닌 패키지의 콘텐츠에 관심을 갖는 것입니다.
u0b34a0f6ae

3
물론 프로그래밍 방식을 의미합니다! 그렇지 않으면 "os.listdir ()을 사용하여 내 솔루션을 롤아웃"에 대해 언급하지 않았을 것입니다.
static_rtti

답변:


145

예, 기반 pkgutil또는 이와 유사한 것을 원합니다. 이렇게하면 달걀이나 zip 형식에 관계없이 모든 패키지를 똑같이 처리 할 수 ​​있습니다 (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 2013

29
나는 m = importer.find_module(modname).load_module(modname)다음과 같이 importer를 사용할 수있었습니다 : 그리고 m모듈입니다. 예를 들면 :m.myfunc()
chrisleague

@chrisleague 저는 python 2.7에서 ur 메소드를 사용하고 있었지만 이제는 python 3.4로 넘어 가야하므로 python 3에서 pkutil.iter_modules가 (module_loader, name, ispkg) 대신 (module_finder, name, ispkg)를 산출한다는 것을 알고 있습니다. 이전처럼 작동하도록하려면 어떻게해야합니까?
crax apr

첫 번째 예제는 다음 오류를 생성합니다. "AttributeError : ' module'object has no attribute ' _path_ '" 이것이 Python 버전과 관련이 있습니까? (저는 Python 2.7을 사용합니다)
Apostolos

@Apostolos, 경로의 양쪽에 하나의 밑줄 만 사용하고 있습니다 (예 :) _path_. 양쪽에 2 개, 총 4 개 (예 :)가 있어야합니다 __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
Mechanical snail

1
두 번째 예제는 다음 오류를 생성합니다. "AttributeError : ' module'object has no attribute ' _path_ '" - 'scipy'로 테스트하지 않았지만 몇 가지 다른 패키지로 테스트했습니다. 이것이 파이썬 버전과 관련이 있습니까? (저는 Python 2.7을 사용합니다)
Apostolos

1
@Apostolos는 : 두 개의 밑줄 (이 있어야합니다 _) 전후 path-되어 사용package.__path__ 하기보다는 package._path_. 코드를 다시 입력하는 것보다 잘라서 붙여 넣는 것이 더 쉬울 수 있습니다.
unutbu

내가 댓글을 썼을 때 두 사람이 있었다! :) 그러나 그들은 시스템에 의해 제거되었습니다. 내 잘못이야; 나는 세 개의 밑줄을 넣어야했다. 하지만 이탤릭체를 사용하고 싶다면 괜찮을 것입니다. ... 손실 손실 상황입니다. :) 어쨌든, 코드를 실행할 때 당연히 두 가지를 사용했습니다. (코드를 복사하여 붙여 넣었습니다.)
Apostolos

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

확실히 정리하고 개선 할 수 있습니다.

편집 : 약간 더 좋은 버전이 있습니다.

>>> [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 2009
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.