Bagaimana cara mendapatkan jalur dan nama file yang sedang dieksekusi?

482

Saya memiliki skrip yang memanggil file skrip lain tetapi saya perlu mendapatkan filepath dari file yang sedang berjalan dalam proses.

Sebagai contoh, katakanlah saya punya tiga file. Menggunakan execfile :

  • script_1.pypanggilan script_2.py.
  • Pada gilirannya, script_2.pypanggilan script_3.py.

Bagaimana saya bisa mendapatkan nama file dan jalur script_3.py, dari kode di dalamscript_3.py , tanpa harus meneruskan informasi itu sebagai argumen dari script_2.py?

(Melaksanakan os.getcwd()mengembalikan filepath skrip awal asli bukan file saat ini.)

sinar
sumber
2
os.path.realpath ( file )
Girish Gupta

Jawaban:

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
Pat Notz
sumber
11
WASPADALAH: Panggilan ini tidak memberikan hasil yang sama dengan lingkungan yang berbeda. Pertimbangkan untuk menerima jawaban Usagi di bawah ini: stackoverflow.com/a/6628348/851398
faraday
3
@ Faraday: Bisakah Anda memberikan contoh? Saya telah menjawab pertanyaan serupa menggunakaninspect.getabsfile() dan berhasil untuk semua kasus yang saya coba.
jfs
1
Apakah jawaban @Usagi memang lebih baik?
Dror
4
nah user13993 memakukannya jauh lebih baik
osirisgothra
6
user13993 memang berhasil. Seharusnyaos.path.realpath(__file__)
uchuugaka
566
__file__

seperti yang orang lain katakan. Anda mungkin juga ingin menggunakan os.path.realpath untuk menghilangkan symlink:

import os

os.path.realpath(__file__)
pengguna13993
sumber
14
Kita perlu berhati-hati dengan pendekatan ini karena kadang-kadang __file__mengembalikan 'script_name.py', dan lain kali 'script_name.pyc'. Jadi output tidak stabil.
mechatroner
27
Tapi karena kita hanya menggunakan jalur file ini, itu tidak relevan.
Uwe Koloska
5
ini aneh: ketika menjalankan dari baris perintah "__file__"dalam tanda kutip (sebagai string) memberikan dir dari mana cmd dijalankan, tetapi __file__ (tanpa tanda kutip memberikan path ke file sumber ... mengapa begitu
muon
7
@muon tidak ada pemeriksaan yang dilakukan pada apakah string nama file yang dilewati ada, dan karena jalur file relatif terhadap cwd, itulah os.path.realpathfungsi yang mengasumsikan dirbagian dari path menjadi. os.path.dirname(os.path.realpath(__file__))mengembalikan direktori dengan file. os.path.dirname(os.path.realpath("__file__"))mengembalikan cwd. os.path.dirname(os.path.realpath("here_be_dragons"))juga mengembalikan cwd.
Jamie Bull
86

Pembaruan 2018-11-28:

Berikut ini adalah ringkasan percobaan dengan Python 2 dan 3. With

main.py - menjalankan foo.py
foo.py - menjalankan lib / bar.py
lib / bar.py - mencetak ekspresi 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__                               |

Untuk Python 2, mungkin lebih jelas untuk beralih ke paket sehingga dapat menggunakan from lib import bar- cukup tambahkan __init__.pyfile kosong ke dua folder.

Untuk Python 3, execfiletidak ada - alternatif terdekat adalah exec(open(<filename>).read()), meskipun ini mempengaruhi bingkai tumpukan. Ini paling sederhana untuk hanya menggunakan import foodan import lib.bar- tidak __init__.pyperlu file.

Lihat juga Perbedaan antara impor dan execfile


Jawaban asli:

Berikut adalah eksperimen berdasarkan jawaban di utas ini - dengan Python 2.7.10 di Windows.

Yang berbasis tumpukan adalah satu-satunya yang tampaknya memberikan hasil yang dapat diandalkan. Dua yang terakhir memiliki sintaks terpendek , yaitu -

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

Ini untuk ini ditambahkan ke sys sebagai fungsi! Kredit ke @Usagi dan @pablog

Berdasarkan tiga file berikut, dan menjalankan main.py dari foldernya dengan python main.py(juga mencoba execfile dengan path absolut dan memanggil dari folder terpisah).

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
Brian Burns
sumber
72

Saya pikir ini lebih bersih:

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

dan mendapatkan informasi yang sama dengan:

print inspect.getfile(inspect.currentframe())

Di mana [0] adalah bingkai saat ini di tumpukan (atas tumpukan) dan [1] adalah untuk nama file, naikkan untuk mundur dalam tumpukan yaitu

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

akan menjadi nama file dari skrip yang disebut frame saat ini. Selain itu, menggunakan [-1] akan membawa Anda ke bagian bawah tumpukan, skrip panggilan asli.

Usagi
sumber
4
Jangan rekomendasikan mengandalkan posisi di dalam tuple. Tidak jelas sama sekali data apa yang Anda coba dapatkan ketika membaca kode.
jpmc26
5
inspect.getfile()mengembalikan __file__atribut jika melewati objek modul. inspect.currentframe()mengembalikan modul. Ergo, ini cara mengatakan yang mahal __file__.
Martijn Pieters
inspect.stack()adalah fungsi yang cukup mahal, lebih dari sekadar inspect.currentframe(), dan itu juga memanggil inspect.getfile()objek modul.
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
Neal Xiong
sumber
1
Saya baru saja mencoba komentar @Pat Notz. Saya pikir Anda bisa mendapatkan nama file melalui __file__.
hlin117
Di Python3, os.path.dirnameakan memberi Anda jalur relatif dari tempat Anda menjalankan skrip. misalnya di python ../../test.pydalam os.path.dirnameakan ../../dan bukan jalan mutlak untuk script. Saya mencari abspath tetapi menghapus nama skrip. Elemen pertama dari sys.path tampaknya adalah jawabannya sys.path[0].
aerijman
37

Saran yang ditandai sebagai yang terbaik semuanya benar jika skrip Anda hanya terdiri dari satu file.

Jika Anda ingin mengetahui nama yang dapat dieksekusi (yaitu file root yang diteruskan ke interpreter python untuk program saat ini) dari file yang dapat diimpor sebagai modul, Anda perlu melakukan ini (anggap ini ada dalam file bernama foo.py ):

import inspect

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

Karena hal terakhir ( [-1]) pada stack adalah hal pertama yang masuk ke dalamnya (tumpukan adalah struktur data LIFO / FILO).

Kemudian di file bar.py jika Anda import fooakan mencetak bar.py , bukan foo.py , yang akan menjadi nilai dari semua ini:

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

sumber
Ini bekerja dengan baik tetapi tidak untuk pengujian unit pada gerhana, saya mendapat
rumah
2
Ini adalah cara pengejaan yang mahal sys.modules['__main__'].__file__, sungguh.
Martijn Pieters
14
import os
print os.path.basename(__file__)

ini akan memberi kita nama file saja. yaitu jika abspath file adalah c: \ abcd \ abc.py maka baris ke-2 akan mencetak abc.py

vishal ekhe
sumber
14

Tidak sepenuhnya jelas apa yang Anda maksud dengan "filepath dari file yang sedang berjalan dalam proses". sys.argv[0]biasanya berisi lokasi skrip yang dipanggil oleh juru bahasa Python. Periksa dokumentasi sistem untuk lebih jelasnya.

Seperti yang ditunjukkan oleh @Tim dan @Pat Notz, atribut __file__ menyediakan akses ke

file dari mana modul dimuat, jika itu diambil dari file

Blair Conrad
sumber
1
"print os.path.abspath ( file )" dan "print inspect.getfile (inspect.currentframe ())" tidak berfungsi ketika kita meneruskan program python ke exe win32. Hanya sys.argv [0] yang berfungsi! :) tetapi Anda hanya mendapatkan nama!
aF.
11

Saya memiliki skrip yang harus berfungsi di bawah lingkungan windows. Kode ini terpotong dengan apa yang telah saya selesaikan:

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

itu keputusan yang cukup gila. Tapi itu tidak memerlukan perpustakaan eksternal dan itu adalah hal yang paling penting dalam kasus saya.

garmoncheg
sumber
1
Saya harus "mengimpor os, sys" untuk ini, tetapi sejauh ini jawaban terbaik yang benar-benar mengembalikan hanya jalan tanpa nama file di akhir string.
emmagras
10

Coba ini,

import os
os.path.dirname(os.path.realpath(__file__))
Soumyajit
sumber
8
import os
os.path.dirname(os.path.abspath(__file__))

Tidak perlu memeriksa atau perpustakaan lain.

Ini bekerja untuk saya ketika saya harus mengimpor skrip (dari direktori yang berbeda kemudian skrip yang dieksekusi), yang menggunakan file konfigurasi yang berada di folder yang sama dengan skrip yang diimpor.

Kwuite
sumber
Ini tidak akan menghasilkan jawaban yang diinginkan jika direktori kerja saat ini (os.getcwd) berbeda dari direktori di mana file tersebut berada.
Bantal Besi
2
Bagaimana? Baik untuk saya dalam hal ini. Saya mendapatkan direktori tempat file itu berada.
Michael Mior
@IronPillow mungkin jawaban ini akan membantu Anda dengan apa yang Anda butuhkan. stackoverflow.com/a/41546830/3123191
Kwuite
6
import sys

print sys.path[0]

ini akan mencetak jalur skrip yang saat ini sedang dijalankan

appusajeev
sumber
2
sys.path [0] sangat berguna, tetapi memberikan jalan script1, bukan script3 seperti yang diminta
James
Setidaknya pada OS X, dengan 2.7, saya tidak menemukan ini bisa diandalkan. Ini berfungsi jika mengeksekusi langsung file yang sama. Tidak bekerja dari repl, terutama dari telur yang diimpor
uchuugaka
5

Saya pikir itu hanya __file__ Kedengarannya seperti Anda mungkin juga ingin checkout modul inspeksi .

Pat Notz
sumber
Ahhh ... execfile itu gampang-gampang susah. Lihat posting saya yang lain tentang menggunakan modul inspect.
Pat Notz
4

Kamu bisa menggunakan 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'
PabloG
sumber
4

Karena Python 3 cukup umum, saya ingin memasukkan pathlibjawaban, karena saya percaya itu mungkin sekarang menjadi alat yang lebih baik untuk mengakses informasi file dan path.

from pathlib import Path

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

Jika Anda sedang mencari direktori dari file saat ini, itu adalah semudah menambahkan .parentke Path()pernyataan:

current_path: Path = Path(__file__).parent.resolve()
Doug
sumber
3
import sys
print sys.argv[0]
WBAR
sumber
10
Sayangnya ini hanya berfungsi jika skrip dipanggil dengan path lengkapnya, karena skrip hanya mengembalikan "argumen pertama" pada baris perintah, yang merupakan panggilan ke skrip.
cregox
2

Ini seharusnya bekerja:

import os,sys
filename=os.path.basename(os.path.realpath(sys.argv[0]))
dirname=os.path.dirname(os.path.realpath(sys.argv[0]))
Jahid
sumber
2
print(__file__)
print(__import__("pathlib").Path(__file__).parent)
BaiJiFeiLong
sumber
4
Kode hanya jawaban yang tidak disarankan. Harap tambahkan beberapa penjelasan tentang bagaimana ini menyelesaikan masalah, atau bagaimana ini berbeda dari jawaban yang ada. Dari Ulasan
Nick
1

Untuk mendapatkan direktori skrip pelaksana

 print os.path.dirname( inspect.getfile(inspect.currentframe()))
pbaranski
sumber
1

Saya selalu menggunakan fitur os dari Current Working Directory, atau CWD. Ini adalah bagian dari perpustakaan standar, dan sangat mudah diimplementasikan. Berikut ini sebuah contoh:

    import os
    base_directory = os.getcwd()
Ethan J.
sumber
1
Bisakah Anda mengubah jawaban Anda sehingga itu berlaku untuk pertanyaan yang diajukan? Jawaban ini tidak berlaku untuk pertanyaan "Bagaimana cara saya mendapatkan jalur dan nama file yang sedang dieksekusi? "
Marco
1
Ini memberikan path dari tempat Anda menjalankan perintah python. Jadi sepertinya berfungsi ketika Anda menjalankan python script.pyperintah di folder yang sama dengan Anda, padahal kenyataannya sama dengan berjalan pwddi linux.
George
0

Saya menggunakan pendekatan dengan __file__
os.path.abspath(__file__)
tetapi ada sedikit trik, ia mengembalikan file .py ketika kode dijalankan pertama kali, selanjutnya menjalankan memberi nama file * .pyc
jadi saya tetap dengan:
inspect.getfile(inspect.currentframe())
atau
sys._getframe().f_code.co_filename

mik80
sumber
0

Saya menulis sebuah fungsi yang mempertimbangkan debugger eclipse dan unittest . Ini mengembalikan folder skrip pertama yang Anda luncurkan. Secara opsional Anda dapat menentukan __file__ var, tetapi yang utama adalah Anda tidak perlu membagikan variabel ini di semua hierarki panggilan Anda .

Mungkin Anda dapat menangani tumpukan kasus tertentu yang tidak saya lihat, tetapi bagi saya tidak masalah.

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_))
hayj
sumber
0

Untuk menjaga konsistensi migrasi lintas platform (macOS / Windows / Linux), coba:

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

Qiao Zhang
sumber
2
Ini salah. Ini memberi Anda jalur saat ini, tetapi bukan jalur dari file saat ini.
Charles Plager
0

Cara paling sederhana adalah:

di script_1.py:

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

di script_2.py:

sys.argv[0]

PS: Saya sudah mencoba execfile, tetapi karena membaca script_2.py sebagai string, sys.argv[0]dikembalikan <string>.

Lucas Azevedo
sumber
0

Inilah yang saya gunakan sehingga saya dapat membuang kode saya di mana saja tanpa masalah. __name__selalu didefinisikan, tetapi __file__hanya ditentukan ketika kode dijalankan sebagai file (misalnya tidak dalam IDLE / iPython).

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

Atau, ini dapat ditulis sebagai:

self_name = globals().get('__file__', locals().get('__file__', __name__))
Craymichael
sumber
-2

Sebagian besar jawaban ini ditulis dalam Python versi 2.x atau sebelumnya. Dalam Python 3.x sintaks untuk fungsi cetak telah berubah untuk membutuhkan tanda kurung, yaitu cetak ().

Jadi, ini skor jawaban tinggi sebelumnya dari user13993 di 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

Menjadi dalam 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
pengguna3339488
sumber
-3

jika Anda hanya menginginkan nama file tanpa ./atau .pyAnda dapat mencoba ini

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

file_name akan mencetak skrip Anda dapat menghasilkan apa pun yang Anda inginkan dengan mengubah indeks di dalam []

sapam
sumber
-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)
jscabuzzo
sumber
7
os.getcwd () mengembalikan direktori PROSES KERJA saat ini, bukan direktori dari file yang sedang dieksekusi. Ini mungkin muncul untuk mengembalikan hasil yang benar tetapi ada banyak kasus di mana hasilnya tidak akan menjadi direktori induk file saat ini. Jauh lebih baik menggunakan os.path.dirname ( file ) seperti yang disarankan di atas.
samaspin