폴더에 모든 모듈을로드하는 방법은 무엇입니까?


269

누군가 모듈의 전체 디렉토리를 가져 오는 좋은 방법을 제공 할 수 있습니까?
나는 이와 같은 구조를 가지고있다 :

/Foo
    bar.py
    spam.py
    eggs.py

추가 __init__.py하고 수행 하여 패키지로 변환하려고했지만 from Foo import *원하는 방식으로 작동하지 않았습니다.


2
초기화 평 방법은 매우 정확합니다. 작동하지 않는 코드를 게시 할 수 있습니까?
balpha

9
"작동하지 않음"을 정의 할 수 있습니까? 어떻게 된 거예요? 어떤 오류 메시지가 나타 났습니까?
S.Lott


명백히 더 좋습니다. 그러나 새 모듈을 추가 할 때마다 이러한 성가신 '찾을 수없는'메시지를 처리하고 싶습니까? 작은 모듈 기능이 많은 패키지 디렉토리가 있다면 이것이 가장 좋은 방법이라고 생각합니다. 내 가정은 다음과 같습니다 : 1. 모듈은 코드 정연의 패키지 사용 2. 오히려 간단하다
Ido_f

답변:


400

.py현재 폴더의 모든 python ( ) 파일을 나열하고 __all__변수로 넣습니다 .__init__.py

from os.path import dirname, basename, isfile, join
import glob
modules = glob.glob(join(dirname(__file__), "*.py"))
__all__ = [ basename(f)[:-3] for f in modules if isfile(f) and not f.endswith('__init__.py')]

57
기본적으로 파이썬 파일을 추가 구성없이 디렉토리에 드롭하고 다른 곳에서 실행되는 스크립트로 실행할 수 있습니다.
Evan Fosmark

5
@NiallDouglas이 답변은 OP가 요청한 특정 질문에 대한 것이며, zip 파일이없고 pyc 파일을 쉽게 포함 할 수 있으며, .pyd 또는 .so libs 등도 잊어 버리고 있습니다.
Anurag Uniyal

35
내가 추가 할 수있는 유일한 것은 if not os.path.basename(f).startswith('_')또는 최소한 if not f.endswith('__init__.py')목록 이해의 끝까지입니다
Pykler

10
보다 강력하게하려면 또한 os.path.isfile(f)입니다 True. 즉, 같은 깨진 심볼릭 링크 및 디렉토리를 필터링 할 somedir.py/(코너의 경우, 나는 ... 인정,하지만 여전히)
MestreLion

12
추가 from . import *설정 후에 __all__는 서브 모듈이 사용 가능하게하려면 .(예로서 module.submodule1, module.submodule2등).
ostrokach

133

포함 할 __all__변수를 추가하십시오 __init__.py.

__all__ = ["bar", "spam", "eggs"]

참조 http://docs.python.org/tutorial/modules.html


163
예,하지만 역동적 인 방법이 있습니까?
Evan Fosmark

27
조합 os.listdir()일부 필터링, 박리의 .py확장자 __all__.

github.com/namgivu/python-import-all/blob/master/error_app.py에서 샘플 코드로 작동하지 않습니다 . 어쩌면 내가 뭔가를 그리워합니까?
Nam G VU

1
나는 스스로 알아 냈습니다-그 모듈에 정의 된 변수 / 객체를 사용하려면 전체 참조 경로를 사용해야합니다 (예 : moduleName.varNameref). stackoverflow.com/a/710603/248616
Nam G VU

1
@NamGVU : 관련 질문에 대한 답변 에서이 코드는 모든 공용 하위 모듈의 이름을 패키지의 네임 스페이스로 가져옵니다.
martineau

54

2017 년 업데이트 : 아마도 importlib대신 사용하고 싶을 것입니다.

를 추가하여 Foo 디렉토리를 패키지로 만듭니다 __init__.py. 그 __init__.py추가 :

import bar
import eggs
import spam

동적이기를 원하기 때문에 (좋은 아이디어 일 수도 있고 아닐 수도 있음) 모든 py 파일을 list dir로 나열하고 다음과 같이 가져 오십시오.

import os
for module in os.listdir(os.path.dirname(__file__)):
    if module == '__init__.py' or module[-3:] != '.py':
        continue
    __import__(module[:-3], locals(), globals())
del module

그런 다음 코드에서 다음을 수행하십시오.

import Foo

이제 다음을 사용하여 모듈에 액세스 할 수 있습니다

Foo.bar
Foo.eggs
Foo.spam

from Foo import *이름 충돌을 포함하고 하드 코드를 분석 할 수있게 몇 가지 이유에 대한 좋은 생각이 아니다.


1
나쁘지는 않지만 .pyc 및 .pyo 파일도 가져올 수 있다는 것을 잊지 마십시오.
Evan Fosmark

7
tbh, 나는 __import__hackish를 발견한다 , 나는 이름을 추가 하고 스크립트의 맨 아래에 __all__두는 것이 낫다고 생각한다from . import *
freeforall tousez

1
나는 이것이 glob 버전보다 더 좋다고 생각합니다.
lpapp

8
__import__일반용이 아니며 대신 interpreter사용 importlib.import_module()합니다.
Andrew_1510

2
첫 번째 예는 매우 도움이되었습니다. 감사합니다! Python 3.6.4 from . import eggs에서는 __init__.pyPython을 가져 오기 전에 이전 에 수행해야 했습니다 . 단지와 함께 import eggs내가 얻을 ModuleNotFoundError: No module named 'eggs'하려고 할 때 import Foo에서 main.py위의 디렉토리에.
Nick

41

Mihail의 답변을 확장하여 파일 경로를 직접 처리하지 않는 것처럼 해킹이 아닌 방법은 다음과 같습니다.

  1. __init__.py아래에 빈 파일을 만듭니다Foo/
  2. 실행
import pkgutil
import sys


def load_all_modules_from_dir(dirname):
    for importer, package_name, _ in pkgutil.iter_modules([dirname]):
        full_package_name = '%s.%s' % (dirname, package_name)
        if full_package_name not in sys.modules:
            module = importer.find_module(package_name
                        ).load_module(full_package_name)
            print module


load_all_modules_from_dir('Foo')

당신은 얻을 것이다:

<module 'Foo.bar' from '/home/.../Foo/bar.pyc'>
<module 'Foo.spam' from '/home/.../Foo/spam.pyc'>

이것은 정답에 이르는 대부분의 방법입니다. ZIP 아카이브를 처리하지만 init 또는 import를 쓰지 않습니다 . 아래의 automodinit를 참조하십시오.
Niall Douglas

1
또 다른 것은 위의 예제는 sys.modules가 모듈이 이미로드되어 있는지 확인하지 않는 것입니다. 확인하지 않으면 위의 모듈이 두 번째로로드됩니다 :)
Niall Douglas

3
코드로 load_all_modules_from_dir ( 'Foo / bar')을 실행하면 "런타임 경고 : 절대 가져 오기를 처리하는 동안 부모 모듈 'Foo / bar'를 찾을 수 없습니다"가 표시됩니다.이를 억제하려면 full_package_name = '.'를 설정해야합니다. dirname.split (os.path.sep) + package_name]) 및 Foo.bar 가져 오기
Alex Dupuy

RuntimeWarningfull_package_name을 전혀 사용하지 않으면 이러한 메시지를 피할 수도 있습니다 importer.find_module(package_name).load_module(package_name).
Artfunkel

RuntimeWarning오류는 부모 (일명있는 dirname)을 가져 와서 (논란의 여지는 있지만 추한 방법으로) 피할 수있다. 이를 수행하는 한 가지 방법은- if dirname not in sys.modules: pkgutil.find_loader(dirname).load_module(dirname)입니다. 물론 dirname단일 구성 요소 상대 경로 인 경우에만 작동합니다 . 슬래시가 없습니다. 개인적으로 나는 기본 package_name을 사용하는 @Artfunkel의 접근 방식을 선호합니다.
dannysauer

31

파이썬, 디렉토리 아래에 모든 파일을 포함하십시오 :

손을 잡아야하는 사람이 일을 할 수없는 초보자에게 적합합니다.

  1. / home / el / foo 폴더를 만들고 / home / el / foo main.py아래 에 파일을 만듭니다. 이 코드를 여기에 넣으십시오.

    from hellokitty import *
    spam.spamfunc()
    ham.hamfunc()
    
  2. 디렉토리 만들기 /home/el/foo/hellokitty

  3. __init__.py아래 에 파일 을 /home/el/foo/hellokitty만들고이 코드를 넣으 십시오 .

    __all__ = ["spam", "ham"]
  4. 이 개 파이썬 파일을 확인하십시오 spam.pyham.py아래/home/el/foo/hellokitty

  5. spam.py 내부에 함수를 정의하십시오.

    def spamfunc():
      print("Spammity spam")
    
  6. ham.py 안에 함수를 정의하십시오 :

    def hamfunc():
      print("Upgrade from baloney")
    
  7. 그것을 실행 :

    el@apollo:/home/el/foo$ python main.py 
    spammity spam
    Upgrade from baloney
    

1
초보자뿐만 아니라 명확한 답변을 원하는 경험이 풍부한 Python 개발자도 있습니다. 감사.
Michael Scheper

그러나 사용하는 import *것은 나쁜 파이썬 코딩 연습으로 간주됩니다. 그것없이 어떻게합니까?
Rachael Blake

16

나는이 문제에 스스로 지쳤다. 그래서 automodinit라는 패키지를 작성하여 고쳤다. http://pypi.python.org/pypi/automodinit/ 에서 얻을 수 있습니다 .

사용법은 다음과 같습니다.

  1. automodinit패키지를 setup.py종속성에 포함하십시오 .
  2. 다음과 같이 __init__.py 파일을 모두 바꾸십시오.
__all__ = [ "다시 작성하겠습니다"]
# 위의 줄이나이 줄을 수정하지 마십시오!
가져 오기 automodinit
automodinit.automodinit (__ name__, __file__, globals ())
델 자동 모드
# 당신이 원하는 다른 것은 여기에 갈 수 있습니다, 그것은 수정되지 않습니다.

그게 다야! 이제 모듈을 가져 오면 __all__이 모듈의 .py [co] 파일 목록으로 설정되고 입력 한 것처럼 각 파일을 가져옵니다.

for x in __all__: import x

따라서 "from M import *"의 효과는 "import M"과 정확히 일치합니다.

automodinit ZIP 아카이브 내부에서 실행하는 것이 행복하므로 ZIP 안전합니다.


pip는 pypi에 업로드 된 것이 없기 때문에 automodinit를 다운로드 할 수 없습니다.
kanzure

github의 버그 보고서에 감사드립니다. v0.13에서이 문제를 해결했습니다. Niall
Niall Douglas

11

나는 꽤 오래된 게시물을 업데이트하고 있다는 것을 알고 있으며을 사용하려고 시도했지만 automodinitpython3의 설정 프로세스가 깨졌습니다. 따라서 Luca의 답변을 바탕 으로이 문제에 대한 .zip과 작동하지 않을 수있는 더 간단한 답변을 찾았으므로 여기에서 공유해야한다고 생각했습니다.

__init__.py모듈 내 에서 yourpackage:

#!/usr/bin/env python
import os, pkgutil
__all__ = list(module for _, module, _ in pkgutil.iter_modules([os.path.dirname(__file__)]))

아래의 다른 패키지 내에서 yourpackage:

from yourpackage import *

그런 다음 패키지 내에 배치 된 모든 모듈을로드하고 새 모듈을 작성하면 자동으로 가져옵니다. 물론 큰 힘을 가지고 조심스럽게 그런 일을하는 것은 큰 책임이 따릅니다.


6
import pkgutil
__path__ = pkgutil.extend_path(__path__, __name__)
for imp, module, ispackage in pkgutil.walk_packages(path=__path__, prefix=__name__+'.'):
  __import__(module)

5

나는 또한이 문제를 겪었고 이것이 내 해결책이었다.

import os

def loadImports(path):
    files = os.listdir(path)
    imps = []

    for i in range(len(files)):
        name = files[i].split('.')
        if len(name) > 1:
            if name[1] == 'py' and name[0] != '__init__':
               name = name[0]
               imps.append(name)

    file = open(path+'__init__.py','w')

    toWrite = '__all__ = '+str(imps)

    file.write(toWrite)
    file.close()

이 함수 는 폴더의 모든 모듈을 보유 __init__.py하는 __all__변수를 포함하는 파일 (제공된 폴더에)을 파일로 만듭니다 .

예를 들어 다음과 같은 폴더 Test 가 있습니다.

Foo.py
Bar.py

스크립트에서 모듈을 가져 오기를 원합니다.

loadImports('Test/')
from Test import *

이 모든 것을 가져옵니다 Test__init__.py의 파일을 Test지금 포함됩니다 :

__all__ = ['Foo','Bar']

완벽하고 정확하게 내가보고있는 것
uma mahesh

4

몇 가지 수정 사항이있는 Anurag의 예 :

import os, glob

modules = glob.glob(os.path.join(os.path.dirname(__file__), "*.py"))
__all__ = [os.path.basename(f)[:-3] for f in modules if not f.endswith("__init__.py")]

4

제안 된 개선 사항이있는 Anurag Uniyal 답변 !

#!/usr/bin/python
# -*- encoding: utf-8 -*-

import os
import glob

all_list = list()
for f in glob.glob(os.path.dirname(__file__)+"/*.py"):
    if os.path.isfile(f) and not os.path.basename(f).startswith('_'):
        all_list.append(os.path.basename(f)[:-3])

__all__ = all_list  

3

당신의 __init__.py정의를 참조하십시오 __all__. 모듈 - 패키지 문서를 말한다

__init__.py파일은 파이썬 치료 패키지가 들어있는 같은 디렉토리를 만들기 위해 필요합니다; 이는 문자열과 같은 공통 이름을 가진 디렉토리가 나중에 모듈 검색 경로에서 발생하는 유효한 모듈을 실수로 숨기지 않도록하기 위해 수행됩니다. 가장 간단한 경우 __init__.py빈 파일 일 수 있지만 __all__나중에 설명 하는 패키지의 초기화 코드를 실행하거나 변수를 설정할 수도 있습니다.

...

유일한 해결책은 패키지 작성자가 패키지의 명시적인 색인을 제공하는 것입니다. import 문은 다음 규칙을 사용합니다. 패키지 __init__.py코드에서 이름이 지정된 목록을 정의하면 __all__import from package *에서 발생할 때 가져와야하는 모듈 이름 목록으로 간주됩니다. 새 버전의 패키지가 릴리스 될 때이 목록을 최신 상태로 유지하는 것은 패키지 작성자의 책임입니다. 패키지 작성자는 패키지에서 *를 가져 오는 데 사용되지 않는 경우이를 지원하지 않기로 결정할 수도 있습니다. 예를 들어 파일 sounds/effects/__init__.py에 다음 코드가 포함될 수 있습니다.

__all__ = ["echo", "surround", "reverse"]

이는 from sound.effects import *사운드 패키지의 3 개의 명명 된 하위 모듈을 가져 오는 것을 의미 합니다.


3

이것이 지금까지 찾은 가장 좋은 방법입니다.

from os.path import dirname, join, isdir, abspath, basename
from glob import glob
pwd = dirname(__file__)
for x in glob(join(pwd, '*.py')):
    if not x.startswith('__'):
        __import__(basename(x)[:-3], globals(), locals())

2

사용하여 importlib추가 할 수있어 유일한 것입니다

from importlib import import_module
from pathlib import Path

__all__ = [
    import_module(f".{f.stem}", __package__)
    for f in Path(__file__).parent.glob("*.py")
    if "__" not in f.stem
]
del import_module, Path

이로 인해 합법적 인 mypy 문제가 발생 error: Type of __all__ must be "Sequence[str]", not "List[Module]"합니다. __all__import_module기반 접근법을 사용 하는 경우 정의 가 필요하지 않습니다 .
Acumenus

1

표준 라이브러리에서 pkgutil 모듈을보십시오. __init__.py디렉토리에 파일 이 있으면 원하는 것을 정확하게 수행 할 수 있습니다 . __init__.py파일이 비어있을 수 있습니다.


1

이를 위해 모듈을 만들었습니다.이 모듈은 __init__.py다른 보조 파일 에 의존하지 않고 다음 두 줄만 입력하게합니다.

import importdir
importdir.do("Foo", globals())

http://gitlab.com/aurelien-lourot/importdir : 자유롭게 재사용하거나 기여하십시오.


0

importlib로 가져 와서 패키지 에 반복적 으로 추가하십시오 __all__( add작업은 선택 사항입니다) __init__.py.

/Foo
    bar.py
    spam.py
    eggs.py
    __init__.py

# __init__.py
import os
import importlib
pyfile_extes = ['py', ]
__all__ = [importlib.import_module('.%s' % filename, __package__) for filename in [os.path.splitext(i)[0] for i in os.listdir(os.path.dirname(__file__)) if os.path.splitext(i)[1] in pyfile_extes] if not filename.startswith('__')]
del os, importlib, pyfile_extes

pyfile_extes는 어디에 정의되어 있습니까?
Jeppe

그것을 놓쳐서 죄송합니다, 이제 수정되었습니다. 가져 오려는 파이썬 파일의 확장자입니다. 일반적으로py
Cheney

0

from . import *충분히 좋은이 아닌, 이것은 비해 개선 테드 의해 답변 . 특히, __all__이 접근 방식의 사용이 필요하지 않습니다.

"""Import all modules that exist in the current directory."""
# Ref https://stackoverflow.com/a/60861023/
from importlib import import_module
from pathlib import Path

for f in Path(__file__).parent.glob("*.py"):
    module_name = f.stem
    if (not module_name.startswith("_")) and (module_name not in globals()):
        import_module(f".{module_name}", __package__)
    del f, module_name
del import_module, Path

module_name not in globals()주기적으로 반입 될 위험이 있으므로 이미 반입 된 모듈을 다시 반입하지 ​​않도록 주의하십시오 .

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