Làm thế nào để lấy đường dẫn của mô-đun?


757

Tôi muốn phát hiện xem mô-đun đã thay đổi. Bây giờ, sử dụng inotify rất đơn giản, bạn chỉ cần biết thư mục bạn muốn nhận thông báo.

Làm cách nào để truy xuất đường dẫn của mô-đun trong python?


1

9
Nếu bạn vẫn đang tìm kiếm trên trang web này, xin vui lòng cập nhật câu trả lời chính xác cho điều này . Đó là cách sạch hơn so với giải pháp đề xuất và nó cũng hoạt động trong trường hợp __file__không được đặt.
erikbwork

3
@ erikb85: nó không chỉ sạch hơn; inspectgiải pháp dựa trên cơ sở cũng hoạt động cho execfile()trường hợp khi __file__sản xuất tên sai âm thầm.
jfs


import pathlib, module; pathlib.Path(module.__file__).resolve().parentĐây là nền tảng phụ thuộc
MortenB

Câu trả lời:


907
import a_module
print(a_module.__file__)

Thực sự sẽ cung cấp cho bạn đường dẫn đến tệp .pyc đã được tải, ít nhất là trên Mac OS X. Vì vậy, tôi đoán bạn có thể làm:

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

Bạn cũng có thể thử:

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

Để có được thư mục của mô-đun.


54
câu trả lời này làm thế nào để có được đường dẫn của mô-đun bạn nhập, nhưng không phải là mô-đun / tập lệnh bạn đang sử dụng (đối với tập lệnh bạn đang chạy, __file__không phải là một đường dẫn đầy đủ, nó là tương đối). Đối với tệp tôi đang ở, tôi phải nhập một mô-đun khác từ cùng thư mục và thực hiện như hiển thị ở đây. Có ai biết một cách thuận tiện hơn?
Ben Bryant

5
@hbdgaf khá chắc chắn không có thứ gì được tích hợp sẵnself.__file__
Dan Passaro

26
@BenBryant @hbdgaf os.path.dirname(__file__)hoạt động tốt với tôi và trả về đường dẫn abs của thư mục của mô-đun.
Niccolò

9
Tôi đã thử làm điều này và nhận được dấu vết: AttributeError: 'module' object has no attribute '__file__'
Dorian Dore

5
@DorianDore Tôi đã làm rối các mô-đun một chút và tìm ra giải pháp path = module.__path__.__dict__["_path"][0], nhưng tôi không chắc nó có khả dụng hay không nếu nó không khác nhau giữa các phiên bản python. Nó hoạt động với tôi, không giống như câu trả lời này mang lại cho tôi cùng một lỗi và inspectcâu trả lời tăng lên TypeError: <module 'module' (namespace)> is a built-in module...
Jezor

279

inspectmô-đun trong python.

Tài liệu chính thức

Mô-đun kiểm tra cung cấp một số chức năng hữu ích để giúp nhận thông tin về các đối tượng sống như mô-đun, lớp, phương thức, hàm, tracebacks, đối tượng khung và đối tượng mã. Ví dụ, nó có thể giúp bạn kiểm tra nội dung của một lớp, lấy mã nguồn của một phương thức, trích xuất và định dạng danh sách đối số cho một hàm hoặc lấy tất cả thông tin bạn cần để hiển thị theo dõi chi tiết.

Thí dụ:

>>> 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
Bạn cũng có thể sử dụng inspectđể lấy tên của tệp hiện tại; xem stackoverflow.com/a/50905/320036
z0r

5
Tôi đã googled câu hỏi này nhiều lần và đây là câu trả lời hợp lý nhất tôi từng thấy! Vui lòng cập nhật thông tin vềinspect.currentframe()
erikbwork 18/12/13

các inspect.getfile()phương pháp không làm việc với các mô-đun _io, nhưng hoạt động với các mô-đun io.
smwikipedia

70

Như các câu trả lời khác đã nói, cách tốt nhất để làm điều này là __file__(thể hiện lại bên dưới). Tuy nhiên, có một cảnh báo quan trọng, đó là __file__KHÔNG tồn tại nếu bạn đang tự chạy mô-đun (ví dụ như __main__).

Ví dụ: giả sử bạn có hai tệp (cả hai tệp này đều nằm trên PYTHONPATH của bạn):

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

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

Chạy foo.py sẽ cho đầu ra:

/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

TUY NHIÊN nếu bạn cố gắng tự chạy bar.py, bạn sẽ nhận được:

/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 

Hi vọng điêu nay co ich. Sự cảnh báo này làm tôi mất rất nhiều thời gian và nhầm lẫn trong khi thử nghiệm các giải pháp khác được trình bày.


5
Trong trường hợp này, bạn có thể sử dụng sys.argv [0] thay cho tệp .
Jimothy

4
Đó có phải là một cảnh báo cụ thể phiên bản? Trong 2.6 và 2.7, tôi thành công dựa vào tệp , tệp này hoạt động khi tên __ == '__ chính '. Trường hợp thất bại duy nhất tôi thấy là với " tệp in python -c '". Tôi sẽ thêm rằng đôi khi tệp có thể là '<stdin>', điều này xảy ra khi các IDE như emacs thực thi bộ đệm hiện tại.
Paul Du Bois

1
Lưu ý rằng các ký tự "__" dẫn đầu và in đậm, vì vậy hãy ghi nhớ điều đó khi đọc các bình luận trước :-P
Paul Du Bois

1
@PaulDuBois Bạn có thể bao quanh nó w / back tics: ` __file__` trở thành__file__
fncomp

1
Làm thế nào để bạn có được NameError? @ Paul Du Bois: Tôi đã thử Python 2,3-3,4 và __file__được xác định tuy nhiên tôi chạy tập tin Python: python a.py, python -ma, ./a.py.
jfs

43

Tôi cũng sẽ cố gắng giải quyết một vài biến thể cho câu hỏi này:

  1. tìm đường dẫn của tập lệnh được gọi
  2. tìm đường dẫn của tập lệnh hiện đang thực thi
  3. tìm thư mục của tập lệnh được gọi

(Một số câu hỏi này đã được hỏi về SO, nhưng đã bị đóng dưới dạng trùng lặp và được chuyển hướng ở đây.)

Hãy cẩn thận khi sử dụng __file__

Đối với một mô-đun mà bạn đã nhập:

import something
something.__file__ 

sẽ trả về đường dẫn tuyệt đối của mô-đun. Tuy nhiên, được cung cấp tập lệnh folowing foo.py:

#foo.py
print '__file__', __file__

Gọi nó bằng 'python foo.py' Sẽ trả lại đơn giản là 'foo.py'. Nếu bạn thêm một shebang:

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

và gọi nó bằng cách sử dụng ./foo.py, nó sẽ trả về './foo.py'. Gọi nó từ một thư mục khác, (ví dụ: đặt foo.py vào thanh thư mục), sau đó gọi một trong hai

python bar/foo.py

hoặc thêm một shebang và thực hiện trực tiếp tệp:

bar/foo.py

sẽ trả về 'bar / foo.py' ( đường dẫn tương đối ).

Tìm thư mục

Bây giờ đi từ đó để có được thư mục, os.path.dirname(__file__)cũng có thể là khó khăn. Ít nhất trên hệ thống của tôi, nó trả về một chuỗi trống nếu bạn gọi nó từ cùng thư mục với tệp. Ví dụ.

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

sẽ xuất ra:

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

Nói cách khác, nó trả về một chuỗi rỗng, vì vậy điều này có vẻ không đáng tin nếu bạn muốn sử dụng nó cho tệp hiện tại (trái ngược với tệp của mô-đun đã nhập). Để giải quyết vấn đề này, bạn có thể gói nó trong một cuộc gọi để từ chối:

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

mà xuất ra một cái gì đó như:

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

Lưu ý rằng abspath () KHÔNG giải quyết các liên kết tượng trưng. Nếu bạn muốn làm điều này, sử dụng realpath () thay thế. Ví dụ: tạo một symlink file_import_testing_link trỏ đến file_import_testing.py, với nội dung sau:

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

thực thi sẽ in các đường dẫn tuyệt đối giống như:

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

file_import_testing_link -> file_import_testing.py

Sử dụng kiểm tra

@SummerBreeze đề cập đến việc sử dụng mô-đun kiểm tra .

Điều này dường như hoạt động tốt và khá ngắn gọn, cho các mô-đun nhập khẩu:

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

ngoan ngoãn trả lại con đường tuyệt đối. Tuy nhiên, để tìm đường dẫn của tập lệnh hiện đang thực thi, tôi không thấy cách nào để sử dụng tập lệnh này.


1
notify.getfile (os) giống như os .__ file__ từ mã: def getfile (object): "" "Tìm ra nguồn hoặc tệp được biên dịch mà một đối tượng được định nghĩa trong." (object, ' file '): đối tượng trả về .__ file__
idanzalz

4
Bạn có thể sử dụng inspect.getfile(inspect.currentframe())để có được đường dẫn của tập lệnh hiện đang chạy.
jbochi

33

Tôi không hiểu tại sao không ai nói về điều này, nhưng với tôi giải pháp đơn giản nhất là sử dụng imp.find_module ("modulename") (tài liệu ở đây ):

import imp
imp.find_module("os")

Nó cung cấp một tuple với đường dẫn ở vị trí thứ hai:

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

Ưu điểm của phương pháp này so với phương thức "kiểm tra" là bạn không cần nhập mô-đun để làm cho nó hoạt động và bạn có thể sử dụng một chuỗi trong đầu vào. Hữu ích khi kiểm tra các mô-đun được gọi trong một kịch bản khác chẳng hạn.

CHỈNH SỬA :

Trong python3, importlibmô-đun nên làm:

Tài liệu của importlib.util.find_spec:

Trả về thông số kỹ thuật cho mô-đun được chỉ định.

Đầu tiên, sys.modules được kiểm tra để xem liệu mô-đun đã được nhập chưa. Nếu vậy, thì sys.modules [tên]. thông số kỹ thuật được trả lại. Nếu điều đó xảy ra được đặt thành Không, thì ValueError được nâng lên. Nếu mô-đun không có trong sys.modules, thì sys.meta_path được tìm kiếm cho một thông số phù hợp với giá trị của 'đường dẫn' được cung cấp cho người tìm. Không được trả lại nếu không có thông số kỹ thuật có thể được tìm thấy.

Nếu tên dành cho mô hình con (chứa dấu chấm), mô đun mẹ sẽ tự động được nhập.

Các đối số tên và gói hoạt động giống như importlib.import_module (). Nói cách khác, tên mô-đun tương đối (có dấu chấm hàng đầu) hoạt động.


2
imp KHÔNG được khấu hao trong python 2 (phiên bản hiện tại 2.7.13). imp được khấu hao trong python 3 kể từ 3.4. Nhập khẩu sẽ được sử dụng trong python 3 thay thế. Tôi thích giải pháp này, vì nó thậm chí hoạt động khi quá trình nhập thực tế sẽ thất bại (ví dụ: vì mô-đun 64 bit cho động cơ 32 bit)
mdew

Và thật sự rất tuyệt khi cố gắng tìm đường dẫn 64 bit sqlite3 và nhập thất bại. Hoàn hảo.
rahvin_t

2
importlib.machinery.PathFinder().find_module("os").get_filename()Thay thế ngắn nhất imp.find_modulemà tôi đã tìm thấy trong Python3 +. Nếu bất cứ ai đang tìm kiếm việc sử dụng importlib.util.find_spec.
Torxed

Phương pháp này hoạt động mà không cần nhập mô-đun thực tế, điều này thật tuyệt vì tôi đang sử dụng phương pháp này để tìm ra phiên bản nào của mô-đun đang được nhập từ máy tính dùng chung.
Gouda

19

Điều này là tầm thường.

Mỗi mô-đun có một __file__biến hiển thị đường dẫn tương đối của nó từ nơi bạn đang ở ngay bây giờ.

Do đó, việc nhận một thư mục cho mô-đun để thông báo cho nó rất đơn giản như:

os.path.dirname(__file__)

14
Hầu nhưng không hoàn toàn đúng - tập tinkhông "liên quan đến nơi bạn đang ở ngay bây giờ"; khi nó tương đối (sẽ chỉ khi có các đường dẫn tương đối trong sys.path), nó tương đối với vị trí của bạn khi mô-đun được tải .
Charles Duffy

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

1
không hoạt động trên Linux python 2.6 của tôi vì __file__chỉ là dir / test.py, abspath liên quan đến cwd để hoàn thành tên đường dẫn không phải là kết quả mong muốn, nhưng nếu bạn nhập mô-đun thì m.__file__sẽ cho kết quả mong muốn.
Ben Bryant

10
import module
print module.__path__

Gói hỗ trợ thêm một thuộc tính đặc biệt , __path__. Đây được khởi tạo là một danh sách chứa tên của thư mục chứa gói __init__.pytrước khi mã trong tệp đó được thực thi. Biến này có thể được sửa đổi; làm như vậy ảnh hưởng đến các tìm kiếm trong tương lai cho các mô-đun và gói con có trong gói.

Mặc dù tính năng này không thường xuyên cần thiết, nhưng nó có thể được sử dụng để mở rộng tập hợp các mô-đun được tìm thấy trong một gói.

Nguồn


9

Tiện ích dòng lệnh

Bạn có thể tinh chỉnh nó thành một tiện ích dòng lệnh,

python-which <package name>

nhập mô tả hình ảnh ở đây


Tạo nên /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__)

Làm cho nó thực thi

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

7

Vì vậy, tôi đã dành một khoảng thời gian hợp lý để làm điều này với py2exe Vấn đề là lấy thư mục cơ sở của tập lệnh cho dù nó đang được chạy dưới dạng tập lệnh python hay dưới dạng thực thi py2exe. Ngoài ra, để nó hoạt động cho dù nó đang được chạy từ thư mục hiện tại, thư mục khác hay (đây là phần khó nhất) từ đường dẫn của hệ thống.

Cuối cùng, tôi đã sử dụng phương pháp này, sử dụng sys.f Frozen như một chỉ báo chạy trong 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__))

7

bạn chỉ có thể nhập mô-đun của mình sau đó nhấn tên của nó và bạn sẽ có đường dẫn đầy đủ

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

4

Nếu bạn muốn truy xuất đường dẫn gốc của gói từ bất kỳ mô-đun nào, các công việc sau (đã được thử nghiệm trên Python 3.6):

from . import __path__ as ROOT_PATH
print(ROOT_PATH)

Đường __init__.pydẫn chính cũng có thể được tham chiếu bằng cách sử dụng __file__thay thế.

Hi vọng điêu nay co ich!


3

Nếu cảnh báo duy nhất của việc sử dụng __file__là khi hiện tại, thư mục tương đối trống (nghĩa là khi chạy dưới dạng tập lệnh từ cùng thư mục có tập lệnh), thì một giải pháp tầm thường là:

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

Và kết quả:

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

Bí quyết là ở or '.'sau khi dirname()cuộc gọi. Nó đặt dir là ., có nghĩa là thư mục hiện tại và là một thư mục hợp lệ cho bất kỳ chức năng liên quan đến đường dẫn.

Vì vậy, sử dụng abspath()là không thực sự cần thiết. Nhưng nếu bạn vẫn sử dụng nó, thì không cần dùng mẹo: abspath()chấp nhận các đường dẫn trống và diễn giải đúng nó là thư mục hiện tại.


Tốt hơn nên trao đổi thứ tự và chỉ sử dụng os.path.dirname(os.path.abspath(__file__))vì sau đó bạn không phải lo lắng về các đường dẫn tương đối. Một cơ hội ít hơn cho các lỗi.
szali

3

Tôi muốn đóng góp với một kịch bản chung (trong Python 3) và khám phá một vài cách tiếp cận với nó.

Hàm dựng sẵn open () chấp nhận đường dẫn tương đối hoặc tuyệt đối làm đối số đầu tiên của nó. Đường dẫn tương đối được coi là tương đối với thư mục làm việc hiện tại, do đó nên chuyển đường dẫn tuyệt đối đến tệp.

Nói một cách đơn giản, nếu bạn chạy tệp tập lệnh với đoạn mã sau, không đảm bảo rằng example.txttệp sẽ được tạo trong cùng thư mục chứa tệp tập lệnh:

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

Để sửa mã này, chúng ta cần lấy đường dẫn đến tập lệnh và làm cho nó tuyệt đối. Để đảm bảo đường dẫn là tuyệt đối, chúng ta chỉ cần sử dụng hàm os.path.realpath () . Để có được đường dẫn đến tập lệnh, có một số hàm phổ biến trả về các kết quả đường dẫn khác nhau:

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

Cả hai hàm os.getcwd ()os.path.realpath () trả về kết quả đường dẫn dựa trên thư mục làm việc hiện tại . Nói chung không phải những gì chúng ta muốn. Phần tử đầu tiên của danh sách sys.argvđường dẫn của tập lệnh gốc (tập lệnh bạn chạy) bất kể bạn gọi danh sách đó trong chính tập lệnh gốc hay trong bất kỳ mô-đun nào. Nó có thể có ích trong một số tình huống. Biến __file__ chứa đường dẫn của mô-đun mà nó được gọi.


Đoạn mã sau đây tạo chính xác một tệp example.txttrong cùng thư mục chứa tập lệnh:

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

with open(filepath, 'w'):
    pass

3

Nếu bạn muốn biết đường dẫn tuyệt đối từ tập lệnh của mình, bạn có thể sử dụng đối tượng Đường dẫn :

from pathlib import Path

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

phương thức cwd ()

Trả về một đối tượng đường dẫn mới đại diện cho thư mục hiện tại (như được trả về bởi os.getcwd ())

phương thức giải quyết ()

Làm cho đường dẫn tuyệt đối, giải quyết bất kỳ liên kết tượng trưng. Một đối tượng đường dẫn mới được trả về:


1

Từ trong các mô-đun của gói python, tôi đã phải tham khảo một tệp nằm trong cùng thư mục với gói. Ví dụ.

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

Vì vậy, ở trên tôi đã phải gọi maincli.py từ mô đun my_lib_a.py biết rằng top_package và maincli.py nằm trong cùng một thư mục. Đây là cách tôi có đường dẫn đến 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

Dựa trên bài đăng của PlasmaBinturong tôi đã sửa đổi mã.


1

Nếu bạn muốn thực hiện điều này một cách linh hoạt trong một "chương trình", hãy thử mã này:
điểm của tôi là, bạn có thể không biết tên chính xác của mô-đun để "mã hóa cứng" nó. Nó có thể được chọn từ danh sách hoặc có thể hiện không chạy để sử dụng __file__.

(Tôi biết, nó sẽ không hoạt động trong 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'>

Tôi đã cố gắng thoát khỏi vấn đề "toàn cầu" nhưng thấy các trường hợp không hoạt động tôi nghĩ "execfile ()" có thể được mô phỏng trong Python 3 Vì đây là một chương trình, nên nó có thể dễ dàng được đưa vào một phương thức hoặc mô-đun cho tái sử dụng


0

Nếu bạn đã cài đặt nó bằng pip, "pip show" hoạt động rất tốt ('Vị trí')

$ pip hiển thị Detron2

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

Đây là một kịch bản bash nhanh trong trường hợp nó hữu ích cho bất cứ ai. Tôi chỉ muốn có thể đặt một biến môi trường để tôi có thể pushdmã.

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

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

Ví dụ về vỏ:

[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 ~]#
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.