모듈의 경로를 검색하는 방법?


755

모듈이 변경되었는지 감지하고 싶습니다. 이제 inotify를 사용하는 것은 간단합니다. 알림을 받으려는 디렉토리를 알아야합니다.

파이썬에서 모듈의 경로를 어떻게 검색합니까?



9
당신은 여전히이 사이트에 찾는 경우에 정확한 답 업데이트하십시오 . 제안 된 솔루션보다 깨끗하며 __file__설정되지 않은 경우에도 작동합니다 .
erikbwork

3
@ erikb85 : 그것은 더 깨끗할뿐만 아니라; inspect기반 솔루션 은 잘못된 이름을 자동으로 생성 하는 execfile()경우 에도 작동합니다 __file__.
jfs


import pathlib, module; pathlib.Path(module.__file__).resolve().parent이것은 플랫폼에
독립적

답변:


906
import a_module
print(a_module.__file__)

실제로 적어도 Mac OS X에서로드 된 .pyc 파일의 경로를 제공합니다.

import os
path = os.path.abspath(a_module.__file__)

시도해 볼 수도 있습니다 :

path = os.path.dirname(a_module.__file__)

모듈의 디렉토리를 가져옵니다.


54
이것은 가져온 모듈의 경로를 얻는 방법에 있지만 응답하는 모듈 / 스크립트의 경로를 얻는 방법 __file__은 아닙니다 ( 실행중인 스크립트의 경우 전체 경로가 아니며 상대 경로입니다). 내가있는 파일의 경우 동일한 디렉토리에서 다른 모듈을 가져 와서 여기에 표시된대로 수행해야했습니다. 누구나 더 편리한 방법을 알고 있습니까?
벤 브라이언트

5
@hbdgaf 내장 된 것과 같은 것은 없다고 확신합니다self.__file__
Dan Passaro

26
@BenBryant @hbdgaf os.path.dirname(__file__)는 저에게 잘 작동하며 모듈 디렉토리의 abs 경로를 반환합니다.
Niccolò

9
나는 이것을 시도하고 역 추적을 얻는다 : AttributeError: 'module' object has no attribute '__file__'
Dorian Dore

5
@DorianDore 나는 모듈을 조금 엉망으로 만들었고 해결책을 얻었 path = module.__path__.__dict__["_path"][0]지만, 이식 가능한지 또는 파이썬 버전 사이에 다른지 확실하지 않습니다. 그것은 같은 오류와 inspect답변을 올리는 이 답변과 달리 나를 위해 일하고 있습니다 TypeError: <module 'module' (namespace)> is a built-in module...
Jezor

279

inspect파이썬 에는 모듈 이 있습니다 .

공식 문서

inspect 모듈은 모듈, 클래스, 메서드, 함수, 트레이스 백, 프레임 객체 및 코드 객체와 같은 라이브 객체에 대한 정보를 얻는 데 도움이되는 몇 가지 유용한 함수를 제공합니다. 예를 들어, 클래스의 내용을 검사하고, 메소드의 소스 코드를 검색하고, 함수의 인수 목록을 추출 및 형식화하거나, 자세한 역 추적을 표시하는 데 필요한 모든 정보를 얻는 데 도움이 될 수 있습니다.

예:

>>> import os
>>> import inspect
>>> inspect.getfile(os)
'/usr/lib64/python2.7/os.pyc'
>>> inspect.getfile(inspect)
'/usr/lib64/python2.7/inspect.pyc'
>>> os.path.dirname(inspect.getfile(inspect))
'/usr/lib64/python2.7'

7
inspect현재 파일의 이름을 얻는데도 사용할 수 있습니다 .
z0r

5
나는이 질문에 여러 번 봤 그리고 이것은 내가 본 가장 합리적인 답변입니다! 다음에 대한 정보를 업데이트하십시오 :inspect.currentframe()
erikbwork

inspect.getfile()접근 방식은 모듈 _io에서는 작동하지 않지만 모듈 에서는 작동합니다 io.
smwikipedia 1

70

다른 답변에서 말했듯 이이 작업을 수행하는 가장 좋은 방법은 __file__(아래에 다시 설명)입니다. 그러나 중요한 경고 __file__가 있습니다 __main__. 즉, 모듈을 자체적으로 실행하는 경우에는 존재하지 않습니다 (예 :) .

예를 들어, 두 개의 파일 (둘 다 PYTHONPATH에 있음)이 있다고 가정하십시오.

#/path1/foo.py
import bar
print(bar.__file__)

#/path2/bar.py
import os
print(os.getcwd())
print(__file__)

foo.py를 실행하면 다음과 같이 출력됩니다 :

/path1        # "import bar" causes the line "print(os.getcwd())" to run
/path2/bar.py # then "print(__file__)" runs
/path2/bar.py # then the import statement finishes and "print(bar.__file__)" runs

그러나 bar.py를 스스로 실행하려고하면 다음과 같은 결과가 나타납니다.

/path2                              # "print(os.getcwd())" still works fine
Traceback (most recent call last):  # but __file__ doesn't exist if bar.py is running as main
  File "/path2/bar.py", line 3, in <module>
    print(__file__)
NameError: name '__file__' is not defined 

도움이 되었기를 바랍니다. 이 경고는 제시된 다른 솔루션을 테스트하는 동안 많은 시간과 혼란을 초래했습니다.


5
이 경우 file 대신 sys.argv [0]을 사용할 수 있습니다 .
Jimothy

4
버전 별 경고입니까? 2.6 및 2.7에서, 나는 성공적에 의존하는 파일 파일을 작동하는 경우 이름 __ == '__ 주 '. 내가 본 유일한 실패 사례는 "python -c 'print file '"입니다. 때때로 파일 은 '<stdin>'이 될 수 있으며 emacs와 같은 IDE가 현재 버퍼를 실행할 때 발생합니다.
Paul Du Bois

1
이전 코멘트 - P 읽을 때 최고의 앤 후행 문자는 굵게 단어를 넣어 것은 "__", 그래서 염두에 유지하는 것이 주
폴 뒤 부아

1
@PaulDuBois 당신은 백틱으로 둘러 쌀 수 있습니다 :` __file__` __file__
makes

1
당신은 어떻게 얻 NameError습니까? @ 폴 뒤 부아 : 나는 파이썬 2.3-3.4 시도하고 __file__그러나 내가 파이썬 파일을 실행 정의된다 : python a.py, python -ma, ./a.py.
jfs

43

이 질문에 대해서도 몇 가지 변형을 시도해 보겠습니다.

  1. 호출 된 스크립트의 경로 찾기
  2. 현재 실행중인 스크립트의 경로 찾기
  3. 호출 된 스크립트의 디렉토리 찾기

(이러한 질문 중 일부는 SO에 대해 요청되었지만 중복으로 닫히고 여기로 리디렉션되었습니다.)

사용에 대한주의 사항 __file__

가져온 모듈의 경우 :

import something
something.__file__ 

모듈 의 절대 경로를 반환합니다 . 그러나 다음 스크립트 foo.py가 주어지면 :

#foo.py
print '__file__', __file__

'python foo.py'로 호출하면 단순히 'foo.py'가 반환됩니다. shebang을 추가하는 경우 :

#!/usr/bin/python 
#foo.py
print '__file__', __file__

./foo.py를 사용하여 호출하면 './foo.py'가 반환됩니다. 다른 디렉토리에서 호출 한 후 (예 : 디렉토리 표시 줄에 foo.py 입력)

python bar/foo.py

또는 shebang을 추가하고 파일을 직접 실행하십시오.

bar/foo.py

'bar / foo.py'( 상대 경로) 를 반환 합니다.

디렉토리 찾기

이제 거기에서 디렉토리를 얻으려면 os.path.dirname(__file__)까다로울 수 있습니다. 적어도 내 시스템에서는 파일과 동일한 디렉토리에서 호출하면 빈 문자열을 반환합니다. 전의.

# foo.py
import os
print '__file__ is:', __file__
print 'os.path.dirname(__file__) is:', os.path.dirname(__file__)

출력합니다 :

__file__ is: foo.py
os.path.dirname(__file__) is: 

즉, 빈 문자열을 반환하므로 가져온 파일파일 이 아닌 현재 파일 에 사용하려는 경우 신뢰할 수없는 것처럼 보입니다 . 이 문제를 해결하려면 abspath 호출로 래핑하십시오.

# foo.py
import os
print 'os.path.abspath(__file__) is:', os.path.abspath(__file__)
print 'os.path.dirname(os.path.abspath(__file__)) is:', os.path.dirname(os.path.abspath(__file__))

다음과 같은 결과가 출력됩니다.

os.path.abspath(__file__) is: /home/user/bar/foo.py
os.path.dirname(os.path.abspath(__file__)) is: /home/user/bar

abspath ()는 심볼릭 링크를 해결하지 않습니다. 이 작업을 수행하려면 realpath ()를 대신 사용하십시오. 예를 들어, 다음 내용으로 file_import_testing.py를 가리키는 symlink file_import_testing_link를 작성하십시오.

import os
print 'abspath(__file__)',os.path.abspath(__file__)
print 'realpath(__file__)',os.path.realpath(__file__)

실행하면 다음과 같은 절대 경로가 인쇄됩니다.

abspath(__file__) /home/user/file_test_link
realpath(__file__) /home/user/file_test.py

file_import_testing_link-> file_import_testing.py

검사 사용

@SummerBreeze는 inspect를 사용하여 언급합니다. 모듈 합니다.

이것은 가져온 모듈에 대해 잘 작동하는 것으로 보이며 매우 간결합니다.

import os
import inspect
print 'inspect.getfile(os) is:', inspect.getfile(os)

절대 경로를 순종적으로 반환합니다. 그러나 현재 실행중인 스크립트의 경로를 찾기 위해 스크립트를 사용하는 방법을 보지 못했습니다.


1
inspect.getfile (os)는 코드에서 os .__ file__과 같습니다. def getfile (object) : "" "ismodule (object) : ifattattr 인 경우 (object, ' file ') : return object .__ file__
idanzalz

4
inspect.getfile(inspect.currentframe())현재 실행중인 스크립트의 경로를 얻는 데 사용할 수 있습니다 .
jbochi

33

아무도 이것에 대해 이야기하지 않는 이유를 알지 못하지만 가장 간단한 해결책은 imp.find_module ( "modulename") (documentation here )을 사용하는 것입니다.

import imp
imp.find_module("os")

두 번째 위치에 경로가있는 튜플을 제공합니다.

(<open file '/usr/lib/python2.7/os.py', mode 'U' at 0x7f44528d7540>,
'/usr/lib/python2.7/os.py',
('.py', 'U', 1))

"검사"방법에 비해이 방법의 장점은 모듈을 가져 와서 작동시킬 필요가없고 입력에 문자열을 사용할 수 있다는 것입니다. 예를 들어 다른 스크립트에서 호출 된 모듈을 확인할 때 유용합니다.

편집 :

python3에서 importlib모듈은 다음을 수행해야합니다.

의 문서 importlib.util.find_spec:

지정된 모듈의 스펙을 돌려줍니다.

먼저 sys.modules를 검사하여 모듈을 이미 가져 왔는지 확인합니다. 그렇다면 sys.modules [name]입니다. 투기 이 반환됩니다. 이것이 None으로 설정되면 ValueError가 발생합니다. 모듈이 sys.modules에 없으면 sys.meta_path는 파인더에 제공된 'path'값을 가진 적합한 스펙을 검색합니다. 스펙을 찾을 수 없으면 아무것도 리턴되지 않습니다.

하위 모듈의 이름 인 경우 (점 포함) 상위 모듈을 자동으로 가져옵니다.

이름 및 패키지 인수는 importlib.import_module ()과 동일하게 작동합니다. 다시 말해, 상대 모듈 이름 (점으로 표시)이 작동합니다.


2
imp은 파이썬 2 (현재 버전 2.7.13)에서 감가 상각되지 않습니다. imp는 3.4 이후 파이썬 3에서 감가 상각됩니다. importlib은 파이썬 3에서 대신 사용됩니다. 이 솔루션은 실제 임포트가 실패 할 때에도 작동하기 때문에 (예 : 32 비트 엔진 용 64 비트 모듈)
mdew

그리고 64 비트 sqlite3의 경로를 찾으려고 시도 할 때 정말 좋으며 가져 오기가 실패합니다. 완전한.
rahvin_t

2
importlib.machinery.PathFinder().find_module("os").get_filename()imp.find_modulePython3 +에서 찾은 가장 짧은 대안 . 누구든지의 사용법을 찾고 있다면 importlib.util.find_spec.
Torxed

이 방법은 실제 모듈을 가져 오지 않고 작동합니다. 공유 컴퓨터에서 어떤 버전의 모듈을 가져 오는지 알아내는 데 유용합니다.
Gouda

19

이것은 사소한 것이었다.

각 모듈에는 __file__현재 위치의 상대 경로를 나타내는 변수가 있습니다.

따라서 모듈이이를 알리기위한 디렉토리를 얻는 것은 다음과 같이 간단합니다.

os.path.dirname(__file__)

14
거의 그러나 옳지 않은- 파일 은 "현재 위치와 관련 이 없습니다 "; 상대적인 경우 (sys.path에 상대 경로 가있을 때만) 모듈이로드 된 위치와 관련이 있습니다.
Charles Duffy

17
import os
path = os.path.abspath(__file__)
dir_path = os.path.dirname(path)

1
Linux python 2.6에서는 __file__dir / test.py 이므로 작동하지 않습니다 .abspath는 cwd를 사용하여 원하는 결과가 아닌 경로 이름을 완성하지만 모듈을 가져 오는 경우 m.__file__원하는 결과 를 제공합니다.
벤 브라이언트

10
import module
print module.__path__

패키지는 하나 이상의 특수 속성을 지원합니다 __path__. 이것은 __init__.py해당 파일의 코드가 실행되기 전에 패키지를 보유한 디렉토리의 이름을 포함하는 목록으로 초기화됩니다 . 이 변수는 수정할 수 있습니다. 이렇게하면 패키지에 포함 된 모듈 및 하위 패키지에 대한 향후 검색에 영향을줍니다.

이 기능은 종종 필요하지는 않지만 패키지에있는 모듈 세트를 확장하는 데 사용할 수 있습니다.

출처


9

명령 줄 유틸리티

명령 줄 유틸리티로 조정할 수 있습니다.

python-which <package name>

여기에 이미지 설명을 입력하십시오


창조하다 /usr/local/bin/python-which

#!/usr/bin/env python

import importlib
import os
import sys

args = sys.argv[1:]
if len(args) > 0:
    module = importlib.import_module(args[0])
    print os.path.dirname(module.__file__)

그것을 실행 가능하게 만드십시오

sudo chmod +x /usr/local/bin/python-which

7

그래서 py2exe 로이 작업을 수행하는 데 상당한 시간을 보냈습니다. 파이썬 스크립트 또는 py2exe 실행 파일로 실행 중인지 스크립트의 기본 폴더를 얻는 것이 문제였습니다. 또한 현재 폴더, 다른 폴더에서 실행되었는지 또는 시스템 경로에서 (가장 어려웠는지) 작동하는지 확인하십시오.

결국 나는 py2exe에서 실행 표시기로 sys.frozen을 사용 하여이 접근법을 사용했습니다.

import os,sys
if hasattr(sys,'frozen'): # only when running in py2exe this exists
    base = sys.prefix
else: # otherwise this is a regular python script
    base = os.path.dirname(os.path.realpath(__file__))

7

모듈을 가져 와서 이름을 입력하면 전체 경로를 얻을 수 있습니다.

>>> import os
>>> os
<module 'os' from 'C:\\Users\\Hassan Ashraf\\AppData\\Local\\Programs\\Python\\Python36-32\\lib\\os.py'>
>>>

4

모듈 중 하나에서 패키지의 루트 경로를 검색하려면 다음과 같이 작동합니다 (Python 3.6에서 테스트).

from . import __path__ as ROOT_PATH
print(ROOT_PATH)

대신 기본 __init__.py경로를 사용하여 참조 할 수도 있습니다 __file__.

도움이 되었기를 바랍니다!


3

사용상의 유일한 경고 __file__가 현재, 상대 디렉토리가 비어있는 경우 (즉, 스크립트가있는 동일한 디렉토리에서 스크립트로 실행하는 경우) 간단한 해결책은 다음과 같습니다.

import os.path
mydir = os.path.dirname(__file__) or '.'
full  = os.path.abspath(mydir)
print __file__, mydir, full

그리고 결과 :

$ python teste.py 
teste.py . /home/user/work/teste

트릭은 통화 or '.'dirname()입니다. dir을로 설정합니다 .. 이는 현재 디렉토리 를 의미합니다. 경로 관련 기능에 유효한 디렉토리입니다.

따라서 사용 abspath()이 꼭 필요한 것은 아닙니다. 그러나 어쨌든 그것을 사용하는 경우에는 트릭이 필요하지 않습니다. abspath()빈 경로를 허용하고 현재 디렉토리로 올바르게 해석합니다.


os.path.dirname(os.path.abspath(__file__))상대 경로에 대해 전혀 걱정할 필요가 없으므로 순서를 바꾸고 사용하는 것이 좋습니다. 버그에 대한 기회가 적습니다.
szali

3

하나의 일반적인 시나리오 (Python 3)에 기여하고 이에 대한 몇 가지 접근법을 탐색하고 싶습니다.

내장 함수 open () 은 상대 또는 절대 경로를 첫 번째 인수로 허용합니다. 상대 경로는 현재 작업 디렉토리에 상대적인 것으로 취급 되므로 파일에 절대 경로를 전달하는 것이 좋습니다.

단순히 당신이 다음 코드를 사용하여 스크립트 파일을 실행하는 경우가있다 고 말했다 하지 보장 example.txt파일이 스크립트 파일이있는 같은 디렉토리에 생성됩니다 :

with open('example.txt', 'w'):
    pass

이 코드를 수정하려면 스크립트 경로를 가져와야합니다. 절대 경로를 보장하기 위해 간단히 os.path.realpath () 함수 를 사용하십시오 . 스크립트 경로를 얻으려면 다양한 경로 결과를 반환하는 몇 가지 공통 함수가 있습니다.

  • os.getcwd()
  • os.path.realpath('example.txt')
  • sys.argv[0]
  • __file__

os.getcwd ()os.path.realpath () 함수 는 현재 작업 디렉토리를 기반으로 경로 결과를 리턴합니다 . 일반적으로 우리가 원하는 것이 아닙니다. sys.argv 목록 의 첫 번째 요소 는 루트 스크립트 자체 또는 해당 모듈에서 목록을 호출하는지 여부에 관계없이 루트 스크립트 (실행하는 스크립트 )의 경로입니다 . 상황에 따라 편리 할 수 ​​있습니다. __file__의 변수는 호출 된 모듈로부터의 경로를 포함한다.


다음 코드 example.txt는 스크립트가있는 동일한 디렉토리에 파일 을 올바르게 작성합니다 .

filedir = os.path.dirname(os.path.realpath(__file__))
filepath = os.path.join(filedir, 'example.txt')

with open(filepath, 'w'):
    pass

3

스크립트에서 절대 경로를 알고 싶다면 Path 객체를 사용할 수 있습니다 .

from pathlib import Path

print(Path().absolute())
print(Path().resolve('.'))
print(Path().cwd())

cwd () 메소드

os.getcwd ()에 의해 반환 된 현재 디렉토리를 나타내는 새로운 경로 객체를 반환

resolve () 메소드

심볼릭 링크를 해결하여 경로를 절대적으로 만듭니다. 새로운 경로 객체가 반환됩니다.


1

파이썬 패키지의 모듈 내에서 패키지와 동일한 디렉토리에있는 파일을 참조해야했습니다. 전의.

some_dir/
  maincli.py
  top_package/
    __init__.py
    level_one_a/
      __init__.py
      my_lib_a.py
      level_two/
        __init__.py
        hello_world.py
    level_one_b/
      __init__.py
      my_lib_b.py

따라서 위에서는 top_package와 maincli.py가 같은 디렉토리에 있다는 것을 알고 my_lib_a.py 모듈에서 maincli.py를 호출해야했습니다. maincli.py의 경로를 얻는 방법은 다음과 같습니다.

import sys
import os
import imp


class ConfigurationException(Exception):
    pass


# inside of my_lib_a.py
def get_maincli_path():
    maincli_path = os.path.abspath(imp.find_module('maincli')[1])
    # top_package = __package__.split('.')[0]
    # mod = sys.modules.get(top_package)
    # modfile = mod.__file__
    # pkg_in_dir = os.path.dirname(os.path.dirname(os.path.abspath(modfile)))
    # maincli_path = os.path.join(pkg_in_dir, 'maincli.py')

    if not os.path.exists(maincli_path):
        err_msg = 'This script expects that "maincli.py" be installed to the '\
        'same directory: "{0}"'.format(maincli_path)
        raise ConfigurationException(err_msg)

    return maincli_path

PlasmaBinturong의 게시를 기반으로 코드를 수정했습니다.


1

"프로그램"에서이 작업을 동적으로 수행하려면 다음 코드를 시도하십시오.
내 요점은 모듈을 "하드 코드"할 정확한 이름을 모를 수도 있습니다. __file__을 사용하기 위해 목록에서 선택하거나 현재 실행 중이 아닐 수 있습니다.

(파이썬 3에서는 작동하지 않습니다)

global modpath
modname = 'os' #This can be any module name on the fly
#Create a file called "modname.py"
f=open("modname.py","w")
f.write("import "+modname+"\n")
f.write("modpath = "+modname+"\n")
f.close()
#Call the file with execfile()
execfile('modname.py')
print modpath
<module 'os' from 'C:\Python27\lib\os.pyc'>

"전역"문제를 제거하려고 시도했지만 작동하지 않는 경우를 발견했습니다. "execfile ()"은 Python 3에서 에뮬레이트 될 수 있다고 생각합니다. 이것은 프로그램에 있기 때문에 쉽게 메소드 또는 모듈에 넣을 수 있습니다 재사용.


0

pip를 사용하여 설치 한 경우 "pip show"가 제대로 작동합니다 ( '위치')

$ 핍 쇼 detectron2

Name: detectron2
Version: 0.1
Summary: Detectron2 is FAIR next-generation research platform for object detection and segmentation.
Home-page: https://github.com/facebookresearch/detectron2
Author: FAIR
Author-email: None
License: UNKNOWN
Location: /home/ubuntu/anaconda3/envs/pytorch_p36/lib/python3.6/site-packages
Requires: yacs, tabulate, tqdm, pydot, tensorboard, Pillow, termcolor, future, cloudpickle, matplotlib, fvcore

0

다음은 누구에게나 유용한 bash 스크립트입니다. pushd코드에 할 수 있도록 환경 변수를 설정할 수 있기를 원합니다 .

#!/bin/bash
module=${1:?"I need a module name"}

python << EOI
import $module
import os
print os.path.dirname($module.__file__)
EOI

셸 예제 :

[root@sri-4625-0004 ~]# export LXML=$(get_python_path.sh lxml)
[root@sri-4625-0004 ~]# echo $LXML
/usr/lib64/python2.7/site-packages/lxml
[root@sri-4625-0004 ~]#
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.