developer tip

모듈의 경로를 검색하는 방법은 무엇입니까?

copycodes 2020. 9. 30. 11:02
반응형

모듈의 경로를 검색하는 방법은 무엇입니까?


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

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


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

모듈의 디렉토리를 얻으려면.


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'

다른 답변에서 말했듯이이를 수행하는 가장 좋은 방법은 __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 

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


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

  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)

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


왜 아무도 이것에 대해 이야기하지 않는지 모르겠지만, 나에게 가장 간단한 해결책은 imp.find_module ( "modulename") ( 여기에 문서 )을 사용하는 것입니다.

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

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

수정 :

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

의 문서 importlib.util.find_spec:

지정된 모듈의 사양을 반환합니다.

먼저 sys.modules를 검사하여 모듈을 이미 가져 왔는지 확인합니다. 그렇다면 sys.modules [이름]. 사양 이 반환됩니다. None으로 설정되면 ValueError가 발생합니다. 모듈이 sys.modules에없는 경우 sys.meta_path는 파인더에 제공된 'path'값을 사용하여 적절한 사양을 검색합니다. 스펙을 찾을 수없는 경우 없음이 리턴됩니다.

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

이름 및 패키지 인수는 importlib.import_module ()과 동일하게 작동합니다. 즉, 상대 모듈 이름 (선행 점 포함)이 작동합니다.


이것은 사소한 일이었습니다.

각 모듈에는 __file__현재 위치로부터의 상대 경로를 보여주는 변수가 있습니다.

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

os.path.dirname(__file__)

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

명령 줄 유틸리티

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

python-which <package name>

enter image description here


창조하다 /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

import module
print module.__path__

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

While this feature is not often needed, it can be used to extend the set of modules found in a package.

Source


So I spent a fair amount of time trying to do this with py2exe The problem was to get the base folder of the script whether it was being run as a python script or as a py2exe executable. Also to have it work whether it was being run from the current folder, another folder or (this was the hardest) from the system's path.

Eventually I used this approach, using sys.frozen as an indicator of running in py2exe:

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

you can just import your module then hit its name and you'll get its full path

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

If the only caveat of using __file__ is when current, relative directory is blank (ie, when running as a script from the same directory where the script is), then a trivial solution is:

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

And the result:

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

The trick is in or '.' after the dirname() call. It sets the dir as ., which means current directory and is a valid directory for any path-related function.

Thus, using abspath() is not truly needed. But if you use it anyway, the trick is not needed: abspath() accepts blank paths and properly interprets it as the current directory.


I'd like to contribute with one common scenario (in Python 3) and explore a few approaches to it.

The built-in function open() accepts either relative or absolute path as its first argument. The relative path is treated as relative to the current working directory though so it is recommended to pass the absolute path to the file.

Simply said, if you run a script file with the following code, it is not guaranteed that the example.txt file will be created in the same directory where the script file is located:

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

To fix this code we need to get the path to the script and make it absolute. To ensure the path to be absolute we simply use the os.path.realpath() function. To get the path to the script there are several common functions that return various path results:

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

Both functions os.getcwd() and os.path.realpath() return path results based on the current working directory. Generally not what we want. The first element of the sys.argv list is the path of the root script (the script you run) regardless of whether you call the list in the root script itself or in any of its modules. It might come handy in some situations. The __file__ variable contains path of the module from which it has been called.


The following code correctly creates a file example.txt in the same directory where the script is located:

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

with open(filepath, 'w'):
    pass

From within modules of a python package I had to refer to a file that resided in the same directory as package. Ex.

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

So in above I had to call maincli.py from my_lib_a.py module knowing that top_package and maincli.py are in the same directory. Here's how I get the path to 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

Based on posting by PlasmaBinturong I modified the code.


If you wish to do this dynamically in a "program" try this code:
My point is, you may not know the exact name of the module to "hardcode" it. It may be selected from a list or may not be currently running to use __file__.

(I know, it will not work in Python 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'>

I tried to get rid of the "global" issue but found cases where it did not work I think "execfile()" can be emulated in Python 3 Since this is in a program, it can easily be put in a method or module for reuse.


If you would like to know absolute path from your script you can use Path object:

from pathlib import Path

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

cwd() method

Return a new path object representing the current directory (as returned by os.getcwd())

resolve() method

Make the path absolute, resolving any symlinks. A new path object is returned:


If you want to retrieve the package's root path from any of its modules, the following works (tested on Python 3.6):

from . import __path__ as ROOT_PATH
print(ROOT_PATH)

The main __init__.py path can also be referenced by using __file__ instead.

Hope this helps!

참고URL : https://stackoverflow.com/questions/247770/how-to-retrieve-a-modules-path

반응형