Làm cách nào để có được đường dẫn và tên của tệp hiện đang thực thi?


482

Tôi có các tập lệnh gọi các tệp script khác nhưng tôi cần lấy filepath của tệp hiện đang chạy trong tiến trình.

Ví dụ: giả sử tôi có ba tệp. Sử dụng execfile :

  • script_1.pycác cuộc gọi script_2.py.
  • Lần lượt, script_2.pygọi script_3.py.

Làm cách nào tôi có thể nhận được tên tệp và đường dẫn của script_3.py, từ mã bên trongscript_3.py mà không phải truyền thông tin đó dưới dạng đối số script_2.py?

(Việc thực thi os.getcwd()trả về tập tin khởi đầu của tập lệnh ban đầu chứ không phải tập tin hiện tại.)



2
os.path.realpath ( tập tin )
Girish Gupta

Câu trả lời:


256

p1.py:

execfile("p2.py")

p2.py:

import inspect, os
print (inspect.getfile(inspect.currentframe()) # script filename (usually with path)
print (os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))) # script directory

11
THƯỞNG: Cuộc gọi này không cho kết quả tương tự với các môi trường khác nhau. Cân nhắc chấp nhận câu trả lời của Usagi bên dưới: stackoverflow.com/a/6628348/851398
faraday

3
@faraday: Bạn có thể cung cấp một ví dụ? Tôi đã trả lời câu hỏi tương tự bằng cách sử dụnginspect.getabsfile() và nó hoạt động cho tất cả các trường hợp mà tôi đã thử.
jfs

1
Có thực sự @Usagi trả lời tốt hơn?
Dror

4
nah user13993 đóng đinh nó tốt hơn nhiều
osirisgothra

6
user13993 đã thực sự đóng đinh nó. Nên làos.path.realpath(__file__)
uchuugaka

566
__file__

như những người khác đã nói. Bạn cũng có thể muốn sử dụng os.path.realpath để loại bỏ các liên kết tượng trưng:

import os

os.path.realpath(__file__)

14
Người ta cần cẩn thận với cách tiếp cận này vì đôi khi __file__trả về 'script_name.py' và các lần khác 'script_name.pyc'. Vì vậy, sản lượng không ổn định.
cơ điện tử

27
Nhưng vì chúng tôi chỉ sử dụng đường dẫn của tệp này không liên quan.
Uwe Koloska

5
Điều này thật kỳ lạ: khi chạy từ dòng lệnh "__file__"trong dấu ngoặc kép (dưới dạng chuỗi) sẽ đưa thư mục từ đó cmd được chạy, nhưng __file__ (không có dấu ngoặc kép đưa đường dẫn đến tệp nguồn ... tại sao lại như vậy
muon

7
@muon không có kiểm tra nào được thực hiện về việc có tồn tại một chuỗi tên tệp hay không và vì các đường dẫn tệp có liên quan đến cwd, đó là os.path.realpathchức năng giả định dirmột phần của đường dẫn. os.path.dirname(os.path.realpath(__file__))trả về thư mục với tập tin os.path.dirname(os.path.realpath("__file__"))trả về cwd. os.path.dirname(os.path.realpath("here_be_dragons"))cũng trả lại cwd.
Jamie Bull

86

Cập nhật 2018-11-28:

Dưới đây là tóm tắt các thử nghiệm với Python 2 và 3. Với

main.py - chạy foo.py
foo.py - chạy lib / bar.py
lib / bar.py - in biểu thức filepath

| Python | Run statement       | Filepath expression                    |
|--------+---------------------+----------------------------------------|
|      2 | execfile            | os.path.abspath(inspect.stack()[0][1]) |
|      2 | from lib import bar | __file__                               |
|      3 | exec                | (wasn't able to obtain it)             |
|      3 | import lib.bar      | __file__                               |

Đối với Python 2, việc chuyển sang các gói có thể rõ ràng hơn from lib import bar- chỉ cần thêm __init__.pycác tệp trống vào hai thư mục.

Đối với Python 3, execfilekhông tồn tại - thay thế gần nhất là exec(open(<filename>).read()), mặc dù điều này ảnh hưởng đến các khung ngăn xếp. Đơn giản nhất là chỉ sử dụng import fooimport lib.bar- không __init__.pycần tệp.

Xem thêm Sự khác biệt giữa nhập và thực thi


Câu trả lời gốc:

Đây là một thử nghiệm dựa trên các câu trả lời trong chuỗi này - với Python 2.7.10 trên Windows.

Những người dựa trên ngăn xếp là những người duy nhất dường như cho kết quả đáng tin cậy. Hai cái cuối cùng có cú pháp ngắn nhất , tức là -

print os.path.abspath(inspect.stack()[0][1])                   # C:\filepaths\lib\bar.py
print os.path.dirname(os.path.abspath(inspect.stack()[0][1]))  # C:\filepaths\lib

Đây là những thứ được thêm vào sys dưới dạng hàm! Tín dụng cho @Usagi và @pablog

Dựa trên ba tệp sau đây và chạy main.txt từ thư mục của nó với python main.py(cũng đã thử các tệp thực thi với các đường dẫn tuyệt đối và gọi từ một thư mục riêng).

C: \ filepaths \ main.py: execfile('foo.py')
C: \ filepaths \ foo.py: execfile('lib/bar.py')
C: \ filepaths \ lib \ bar.py:

import sys
import os
import inspect

print "Python " + sys.version
print

print __file__                                        # main.py
print sys.argv[0]                                     # main.py
print inspect.stack()[0][1]                           # lib/bar.py
print sys.path[0]                                     # C:\filepaths
print

print os.path.realpath(__file__)                      # C:\filepaths\main.py
print os.path.abspath(__file__)                       # C:\filepaths\main.py
print os.path.basename(__file__)                      # main.py
print os.path.basename(os.path.realpath(sys.argv[0])) # main.py
print

print sys.path[0]                                     # C:\filepaths
print os.path.abspath(os.path.split(sys.argv[0])[0])  # C:\filepaths
print os.path.dirname(os.path.abspath(__file__))      # C:\filepaths
print os.path.dirname(os.path.realpath(sys.argv[0]))  # C:\filepaths
print os.path.dirname(__file__)                       # (empty string)
print

print inspect.getfile(inspect.currentframe())         # lib/bar.py

print os.path.abspath(inspect.getfile(inspect.currentframe())) # C:\filepaths\lib\bar.py
print os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))) # C:\filepaths\lib
print

print os.path.abspath(inspect.stack()[0][1])          # C:\filepaths\lib\bar.py
print os.path.dirname(os.path.abspath(inspect.stack()[0][1]))  # C:\filepaths\lib
print

72

Tôi nghĩ rằng điều này là sạch hơn:

import inspect
print inspect.stack()[0][1]

và nhận được thông tin tương tự như:

print inspect.getfile(inspect.currentframe())

Trong đó [0] là khung hiện tại trong ngăn xếp (trên cùng của ngăn xếp) và [1] là cho tên tệp, tăng để đi ngược lại trong ngăn xếp tức là

print inspect.stack()[1][1]

sẽ là tên tệp của tập lệnh được gọi là khung hiện tại. Ngoài ra, sử dụng [-1] sẽ đưa bạn đến cuối ngăn xếp, tập lệnh gọi ban đầu.


4
Không khuyên bạn nên dựa vào vị trí bên trong tuple. Không rõ ràng về những dữ liệu bạn đang cố gắng nhận được khi đọc mã.
jpmc26

5
inspect.getfile()trả về __file__thuộc tính nếu thông qua một đối tượng mô-đun. inspect.currentframe()trả về mô-đun. Ergo, đây là một cách nói đắt tiền __file__.
Martijn Pieters

inspect.stack()là một chức năng khá đắt tiền, không chỉ đơn thuần là như vậy inspect.currentframe(), và nó cũng gọi inspect.getfile()một đối tượng mô-đun.
Martijn Pieters

42
import os
os.path.dirname(__file__) # relative directory path
os.path.abspath(__file__) # absolute file path
os.path.basename(__file__) # the file name only

1
Tôi vừa thử bình luận của @Pat Notz. Tôi nghĩ rằng bạn chỉ có thể có được tên tệp thông qua __file__.
hlin117

Trong Python3, os.path.dirnamesẽ cung cấp cho bạn đường dẫn tương đối từ nơi bạn đang chạy tập lệnh. ví dụ trong python ../../test.pyý os.path.dirnamechí ../../và không phải là đường dẫn tuyệt đối đến tập lệnh. Tôi đã tìm kiếm abspath nhưng loại bỏ tên của kịch bản. Yếu tố đầu tiên của sys.path rõ ràng là câu trả lời sys.path[0].
aerijman

37

Các đề xuất được đánh dấu là tốt nhất đều đúng nếu tập lệnh của bạn chỉ bao gồm một tệp.

Nếu bạn muốn tìm ra tên của tệp thực thi (tức là tệp gốc được truyền cho trình thông dịch python cho chương trình hiện tại) từ một tệp có thể được nhập dưới dạng một mô-đun, bạn cần phải làm điều này (giả sử đây là trong một tệp có tên foo.py ):

import inspect

print inspect.stack()[-1][1]

Bởi vì điều cuối cùng ( [-1]) trên ngăn xếp là thứ đầu tiên đi vào nó (ngăn xếp là cấu trúc dữ liệu LIFO / FILO).

Sau đó, trong tệp bar.txt nếu bạn import foosẽ in bar.py , chứ không phải foo.py , đó sẽ là giá trị của tất cả những điều này:

  • __file__
  • inspect.getfile(inspect.currentframe())
  • inspect.stack()[0][1]

Nó hoạt động tốt nhưng không phải để thử nghiệm đơn vị trên nhật thực, tôi đã nhận /home/user/Softwares/eclipse/plugins/org.python.pydev_4.5.5.201603221110/pysrc
hayj

2
Đây là một cách chính tả đắt tiền sys.modules['__main__'].__file__, thực sự.
Martijn Pieters

14
import os
print os.path.basename(__file__)

Điều này sẽ chỉ cung cấp cho chúng tôi tên tệp. tức là nếu abspath của tệp là c: \ abcd \ abc.py thì dòng thứ 2 sẽ in abc.py


14

Nó không hoàn toàn rõ ràng ý của bạn là gì bởi "filepath của tệp hiện đang chạy trong tiến trình". sys.argv[0]thường chứa vị trí của tập lệnh được trình thông dịch Python gọi. Kiểm tra tài liệu sys để biết thêm chi tiết.

Như @Tim và @Pat Notz đã chỉ ra, thuộc tính __file__ cung cấp quyền truy cập vào

tệp mà mô-đun được tải, nếu nó được tải từ một tệp


1
"print os.path.abspath ( file )" và "print notify.getfile (notify.cienframe ())" không hoạt động khi chúng ta chuyển chương trình python sang exe win32. Chỉ sys.argv [0] hoạt động! :) nhưng bạn chỉ có được tên!
aF.

11

Tôi có một kịch bản phải làm việc trong môi trường windows. Đoạn mã này là những gì tôi đã hoàn thành:

import os,sys
PROJECT_PATH = os.path.abspath(os.path.split(sys.argv[0])[0])

Đó là một quyết định khó khăn. Nhưng nó không yêu cầu thư viện bên ngoài và đó là điều quan trọng nhất trong trường hợp của tôi.


1
Tôi đã phải "nhập os, sys" cho việc này, nhưng cho đến nay, đó là câu trả lời tốt nhất thực sự chỉ trả về đường dẫn không có tên tệp ở cuối chuỗi.
emmagras

10

Thử cái này,

import os
os.path.dirname(os.path.realpath(__file__))

8
import os
os.path.dirname(os.path.abspath(__file__))

Không cần kiểm tra hoặc bất kỳ thư viện khác.

Điều này làm việc cho tôi khi tôi phải nhập một tập lệnh (từ một thư mục khác sau đó là tập lệnh đã thực thi), sử dụng tệp cấu hình nằm trong cùng thư mục với tập lệnh đã nhập.


Điều này sẽ không tạo ra câu trả lời mong muốn nếu thư mục làm việc hiện tại (os.getcwd) khác với thư mục chứa tệp.
Gối sắt

2
Làm sao vậy Hoạt động tốt cho tôi trong trường hợp này. Tôi nhận được thư mục tập tin nằm ở.
Michael Mior

@IronPvel có lẽ câu trả lời này sẽ giúp bạn với những gì bạn cần. stackoverflow.com/a/41546830/3123191
Kwuite


6
import sys

print sys.path[0]

điều này sẽ in đường dẫn của tập lệnh hiện đang thực thi


2
sys.path [0] rất hữu ích, nhưng đưa ra đường dẫn của script1, không phải script3 như yêu cầu
James

Ít nhất là trên OS X, với 2.7, tôi không thấy điều này đáng tin cậy. Nó hoạt động nếu thực hiện trực tiếp cùng một tập tin. Không hoạt động từ thay thế, đặc biệt là từ một quả trứng nhập khẩu
uchuugaka

5

Tôi nghĩ đó chỉ là __file__ Âm thanh như bạn cũng có thể muốn kiểm tra mô-đun kiểm tra .


Ahhh ... execfile là khó khăn. Xem bài viết khác của tôi về việc sử dụng các mô-đun kiểm tra.
Pat Notz

4

Bạn có thể dùng inspect.stack()

import inspect,os
inspect.stack()[0]  => (<frame object at 0x00AC2AC0>, 'g:\\Python\\Test\\_GetCurrentProgram.py', 15, '<module>', ['print inspect.stack()[0]\n'], 0)
os.path.abspath (inspect.stack()[0][1]) => 'g:\\Python\\Test\\_GetCurrentProgram.py'

4

Vì Python 3 khá chính thống, tôi muốn đưa ra pathlibcâu trả lời, vì tôi tin rằng giờ đây nó có thể là một công cụ tốt hơn để truy cập thông tin tệp và đường dẫn.

from pathlib import Path

current_file: Path = Path(__file__).resolve()

Nếu bạn đang tìm kiếm thư mục của tệp hiện tại, việc thêm .parentvào Path()câu lệnh sẽ dễ dàng như sau:

current_path: Path = Path(__file__).parent.resolve()

3
import sys
print sys.argv[0]

10
Thật không may, điều này chỉ hoạt động nếu tập lệnh được gọi với đường dẫn đầy đủ của nó, bởi vì nó chỉ trả về "đối số đầu tiên" trên dòng lệnh, đó là cách gọi tập lệnh.
cregox

2

Điều này sẽ làm việc:

import os,sys
filename=os.path.basename(os.path.realpath(sys.argv[0]))
dirname=os.path.dirname(os.path.realpath(sys.argv[0]))

2
print(__file__)
print(__import__("pathlib").Path(__file__).parent)

4
Mã chỉ trả lời được khuyến khích. Vui lòng thêm một số giải thích về cách giải quyết vấn đề này hoặc cách giải quyết vấn đề này khác với các câu trả lời hiện có. Từ đánh giá
Nick

1

Để có được thư mục thực thi tập lệnh

 print os.path.dirname( inspect.getfile(inspect.currentframe()))

1

Tôi luôn luôn sử dụng tính năng os của Thư mục làm việc hiện tại hoặc CWD. Đây là một phần của thư viện tiêu chuẩn, và rất dễ thực hiện. Đây là một ví dụ:

    import os
    base_directory = os.getcwd()

1
Bạn có thể sửa đổi câu trả lời của mình để nó áp dụng cho câu hỏi được đặt ra không? Câu trả lời này không áp dụng cho câu hỏi "Làm cách nào tôi có được đường dẫn và tên của tệp hiện đang thực thi? "
Marco

1
Điều này đưa ra đường dẫn từ nơi bạn chạy lệnh python. Vì vậy, nó có vẻ hoạt động khi bạn chạy python script.pylệnh trong cùng thư mục mà bạn đã có, trong thực tế, nó giống như chạy pwdtrên linux.
George

0

Tôi đã sử dụng cách tiếp cận với __file__
os.path.abspath(__file__)
nhưng có một mẹo nhỏ, nó trả về tệp .py khi mã được chạy lần đầu tiên, các lần chạy tiếp theo sẽ đặt tên của tệp * .pyc
để tôi ở lại:
inspect.getfile(inspect.currentframe())
hoặc
sys._getframe().f_code.co_filename


0

Tôi đã viết một chức năng có tính đến trình gỡ lỗi nhật thực và không đáng tin cậy nhất . Nó trả về thư mục của tập lệnh đầu tiên bạn khởi chạy. Bạn có thể tùy ý chỉ định __file__ var, nhưng điều chính là bạn không phải chia sẻ biến này trên tất cả hệ thống phân cấp cuộc gọi của bạn .

Có thể bạn có thể xử lý các trường hợp cụ thể khác mà tôi không thấy, nhưng đối với tôi nó ổn.

import inspect, os
def getRootDirectory(_file_=None):
    """
    Get the directory of the root execution file
    Can help: http://stackoverflow.com/questions/50499/how-do-i-get-the-path-and-name-of-the-file-that-is-currently-executing
    For eclipse user with unittest or debugger, the function search for the correct folder in the stack
    You can pass __file__ (with 4 underscores) if you want the caller directory
    """
    # If we don't have the __file__ :
    if _file_ is None:
        # We get the last :
        rootFile = inspect.stack()[-1][1]
        folder = os.path.abspath(rootFile)
        # If we use unittest :
        if ("/pysrc" in folder) & ("org.python.pydev" in folder):
            previous = None
            # We search from left to right the case.py :
            for el in inspect.stack():
                currentFile = os.path.abspath(el[1])
                if ("unittest/case.py" in currentFile) | ("org.python.pydev" in currentFile):
                    break
                previous = currentFile
            folder = previous
        # We return the folder :
        return os.path.dirname(folder)
    else:
        # We return the folder according to specified __file__ :
        return os.path.dirname(os.path.realpath(_file_))

0

Để giữ tính nhất quán di chuyển trên các nền tảng (macOS / Windows / Linux), hãy thử:

path = r'%s' % os.getcwd().replace('\\','/')


2
Cái này sai. Điều này giúp bạn có đường dẫn hiện tại, nhưng không phải là đường dẫn của tệp hiện tại.
Charles Plager

0

Cách đơn giản nhất là:

trong script_1.py:

import subprocess
subprocess.call(['python3',<path_to_script_2.py>])

trong script_2.py:

sys.argv[0]

Tái execfilebút : Tôi đã thử , nhưng vì nó đọc script_2.txt dưới dạng chuỗi, đã sys.argv[0]trả về <string>.


0

Đây là những gì tôi sử dụng để tôi có thể ném mã của mình đi bất cứ đâu mà không gặp vấn đề gì. __name__luôn được xác định, nhưng __file__chỉ được xác định khi mã được chạy dưới dạng tệp (ví dụ: không có trong IDLE / iPython).

    if '__file__' in globals():
        self_name = globals()['__file__']
    elif '__file__' in locals():
        self_name = locals()['__file__']
    else:
        self_name = __name__

Ngoài ra, điều này có thể được viết là:

self_name = globals().get('__file__', locals().get('__file__', __name__))

-2

Hầu hết các câu trả lời này được viết bằng Python phiên bản 2.x trở về trước. Trong Python 3.x cú pháp cho hàm in đã thay đổi để yêu cầu dấu ngoặc đơn, tức là print ().

Vì vậy, câu trả lời điểm cao trước đó từ user13993 trong Python 2.x:

import inspect, os
print inspect.getfile(inspect.currentframe()) # script filename (usually with path)
print os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))) # script directory

Trở thành Python 3.x:

import inspect, os
print(inspect.getfile(inspect.currentframe())) # script filename (usually with path)
print(os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))) ) # script directory

-3

nếu bạn chỉ muốn tên tệp mà không có ./hoặc .pybạn có thể thử cái này

filename = testscript.py
file_name = __file__[2:-3]

file_name sẽ in bản kiểm tra mà bạn có thể tạo bất cứ thứ gì bạn muốn bằng cách thay đổi chỉ mục bên trong []


-3
import os

import wx


# return the full path of this file
print(os.getcwd())

icon = wx.Icon(os.getcwd() + '/img/image.png', wx.BITMAP_TYPE_PNG, 16, 16)

# put the icon on the frame
self.SetIcon(icon)

7
os.getcwd () trả về thư mục WORKING hiện tại của PROCESS, không phải thư mục của tệp hiện đang thực thi. Điều này có thể trả về kết quả chính xác nhưng có nhiều trường hợp kết quả không phải là thư mục mẹ của tệp hiện tại. Tốt hơn nhiều để sử dụng os.path.dirname ( tệp ) như được đề xuất ở trên.
samaspin
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.