Dapatkan nama skrip saat ini dengan Python

408

Saya mencoba untuk mendapatkan nama skrip Python yang sedang berjalan.

Saya memiliki skrip yang dipanggil foo.pydan saya ingin melakukan sesuatu seperti ini untuk mendapatkan nama skrip:

print Scriptname
SubniC
sumber

Jawaban:

621

Anda dapat menggunakan __file__untuk mendapatkan nama file saat ini. Ketika digunakan dalam modul utama, ini adalah nama skrip yang awalnya dipanggil.

Jika Anda ingin menghilangkan bagian direktori (yang mungkin ada), Anda dapat menggunakan os.path.basename(__file__).

Sven Marnach
sumber
15
Python 3.2: " Exception NameError: NameError("global name '__file__' is not defined",)"
sdaau
20
@daau: __file__tidak didefinisikan dalam interpreter interaktif, karena tidak ada artinya di sana. Ini diatur oleh implementasi impor, jadi jika Anda menggunakan mekanisme impor non-standar mungkin juga tidak disetel.
Sven Marnach
8
Setidaknya untuk Python 2.7, saya percaya import osdiperlukan untuk ini untuk bekerja. Saya akan menambahkan ini ke dalam jawabannya.
Nick Chammas
14
@ cdunn2001: import osdan import os.pathsepenuhnya setara.
Sven Marnach
2
@ sven-marnach: Oh, Anda benar . Saya telah Melakukannya Salah selama bertahun-tahun!
cdunn2001
136
import sys
print sys.argv[0]

Ini akan mencetak foo.pyuntuk python foo.py, dir/foo.pyuntuk python dir/foo.py, dll. Ini adalah argumen pertama python. (Perhatikan bahwa setelah py2exe, itu akan menjadi foo.exe.)

Chris Morgan
sumber
33
@DenisMalinovsky: tentukan "tidak akan bekerja". Jika Anda menelepon python linkfile.py, di mana linkfile.pysymlink ke realfile.py, sys.argv[0]akan 'linkfile.py', yang mungkin atau mungkin tidak apa yang Anda inginkan; tentu saja itu yang saya harapkan . __file__adalah sama: itu akan terjadi linkfile.py. Jika Anda ingin mencari 'realfile.py'dari 'linkfile.py', coba os.path.realpath('linkfile.py').
Chris Morgan
6
+1 karena (a) sedikit lebih rapi dan (b) masih akan berfungsi dalam modul (di mana variabel file akan menjadi file modul, bukan yang dieksekusi).
robert
Jawaban ini bagus karena berfungsi di IDLE juga. Sebagai catatan, untuk mendapatkan hanya nama file, Anda dapat menulis os.path.basename (sys.argv [0])
Steven Bluen
Lebih penting lagi, ini tidak berfungsi kecuali dari dalam file utama. Jangan gunakan ini, gunakan __file__saja.
Apollys mendukung Monica
APA!!! Apakah Anda pernah mencoba ini? Justru sebaliknya yang benar. Penanya menanyakan nama skrip python yang sedang berjalan - bukan file python yang sedang dieksekusi. Bayangkan Anda memiliki skrip yang, ketika terjadi kesalahan, mencetak nama skrip beserta argumen yang dibolehkan. Anda menempatkannya dalam suatu fungsi, menggunakan salah satu dari 2 teknik ini. Pada titik tertentu, Anda memutuskan untuk memindahkan fungsi ke perpustakaan eksternal. Apakah Anda ingin mencetak nama skrip utama yang sedang berjalan, atau nama file perpustakaan yang sedang dieksekusi?
John Deighan
71

Demi kelengkapan, saya pikir akan bermanfaat untuk merangkum berbagai hasil yang mungkin dan menyediakan referensi untuk perilaku yang tepat dari masing-masing:

  • __file__adalah file yang sedang dieksekusi, sebagaimana dirinci dalam dokumentasi resmi :

    __file__adalah pathname dari file dari mana modul dimuat, jika itu diambil dari file. The __file__atribut mungkin hilang untuk beberapa jenis modul, seperti C modul yang statis terhubung ke penafsir; untuk modul ekstensi yang dimuat secara dinamis dari perpustakaan bersama, itu adalah nama path dari file perpustakaan bersama.

    Dari Python3.4 dan seterusnya, per masalah 18416 , __file__selalu merupakan jalur absolut, kecuali jika file yang sedang dieksekusi adalah skrip yang telah dieksekusi secara langsung (bukan melalui penerjemah dengan -mopsi baris perintah) menggunakan jalur relatif.

  • __main__.__file__(memerlukan pengimporan __main__) dengan mudah mengakses __file__atribut modul utama yang disebutkan di atas , misalnya skrip yang dipanggil dari baris perintah.

  • sys.argv[0](wajib mengimpor sys) adalah nama skrip yang dipanggil dari baris perintah, dan mungkin merupakan jalur absolut, sebagaimana dirinci dalam dokumentasi resmi :

    argv[0]adalah nama skrip (tergantung pada sistem operasi apakah ini nama path lengkap atau tidak). Jika perintah dieksekusi menggunakan -copsi baris perintah ke interpreter, argv[0]diatur ke string '-c'. Jika tidak ada nama skrip yang diteruskan ke interpreter Python, argv[0]adalah string kosong.

    Seperti disebutkan dalam jawaban lain untuk pertanyaan ini , skrip Python yang dikonversi menjadi program yang dapat dieksekusi yang berdiri sendiri melalui alat-alat seperti py2exe atau PyInstaller mungkin tidak menampilkan hasil yang diinginkan ketika menggunakan pendekatan ini (yaitu sys.argv[0]akan menyimpan nama yang dapat dieksekusi daripada nama dari file Python utama dalam executable itu).

  • Jika tidak ada opsi yang disebutkan di atas yang berfungsi, mungkin karena operasi impor yang tidak teratur, modul inspeksi mungkin terbukti bermanfaat. Secara khusus, memohon inspect.getfile(...)pada inspect.currentframe()bisa bekerja, meskipun yang terakhir akan kembaliNone ketika berjalan di sebuah implementasi tanpa Python stack frame.


Menangani tautan simbolis

Jika skrip saat ini adalah tautan simbolik, maka semua yang di atas akan mengembalikan jalur tautan simbolik daripada path file asli dan os.path.realpath(...)harus dipanggil untuk mengekstrak yang terakhir.


Manipulasi lebih lanjut yang mengekstrak nama file yang sebenarnya

os.path.basename(...)dapat dipanggil pada salah satu di atas untuk mengekstrak nama file yang sebenarnya dan os.path.splitext(...)dapat dipanggil pada nama file yang sebenarnya untuk memotong sufiksnya, seperti padaos.path.splitext(os.path.basename(...)) .

Dari Python 3,4 dan seterusnya, per PEP 428 , yang PurePathkelas dari pathlibmodul dapat digunakan juga pada apapun di atas. Secara khusus, pathlib.PurePath(...).namemengekstrak nama file aktual dan pathlib.PurePath(...).stemmengekstraksi nama file aktual tanpa akhiran.

Yoel
sumber
66

Catatan yang __file__akan memberikan file tempat kode ini berada, yang dapat diimpor dan berbeda dari file utama yang ditafsirkan. Untuk mendapatkan file utama, modul __main__ khusus dapat digunakan:

import __main__ as main
print(main.__file__)

Catatan yang __main__.__file__berfungsi di Python 2.7 tetapi tidak di 3.2, jadi gunakan sintaks import-as seperti di atas untuk membuatnya portabel.

Ambroz Bizjak
sumber
Ini berfungsi dalam banyak kasus tetapi tidak ketika saya menggunakan rPythonpaket dari Rbahasa. Itu pasti kasus luar biasa yang terlalu sulit untuk ditangani.
Leonid
Memang, paket rPython menanamkan interpreter python, yang berarti tidak ada file 'utama' seperti ada ketika python berjalan sendiri (Anda akan menemukan perilaku yang sama kapan saja python disematkan). Itu mengimpor secara __main__internal, untuk digunakan dalam melewati variabel antara Rdan python, jadi itu akan relatif mudah untuk membuatnya ditetapkan __main__.__file__sebelum memanggil yang lain, tapi saya bahkan tidak yakin apa yang akan menjadi nilai yang sesuai dalam kasus ini.
Perkins
42

Jawaban di atas baik. Tetapi saya menemukan metode ini lebih efisien menggunakan hasil di atas.
Ini menghasilkan nama file skrip aktual bukan jalur.

import sys    
import os    
file_name =  os.path.basename(sys.argv[0])
Manoj Sahu
sumber
1
Saya juga suka membagi ekstensi, jadi saya menggunakan: os.path.splitext (os.path.basename (sys.argv [0])) [0]
RufusVS
19

Untuk versi Python modern (3.4+), Path(__file__).nameharus lebih idiomatis. Juga, Path(__file__).stemmemberi Anda nama skrip tanpa .pyekstensi.

Emil Melnikov
sumber
NameError: name 'Path' tidak didefinisikan
RufusVS
5
Anda harus from pathlib import Pathterlebih dahulu.
Emil Melnikov
"modern" berarti Python 3.x?
einpoklum
1
@einpoklum pathlibdiperkenalkan dengan Python 3.4, jadi harusnya mulai dari Python 3.4.
Andrey Semakin
9

Coba ini:

print __file__
demo
sumber
9

Catatan: Jika Anda menggunakan Python 3+, Anda harus menggunakan fungsi print ()

Dengan asumsi bahwa nama file adalah foo.py, potongan di bawah ini

import sys
print sys.argv[0][:-3]

atau

import sys
print sys.argv[0][::-1][3:][::-1]

Adapun perluasan lain dengan lebih banyak karakter, misalnya nama file foo.pypy

import sys
print sys.argv[0].split('.')[0]

Jika Anda ingin mengekstrak dari jalur absolut

import sys
print sys.argv[0].split('/')[-1].split('.')[0]

akan menampilkan foo

xtonousou
sumber
1
sys.argv [0] [: - 3] akan melakukan
kon psik
@konpsych itu lebih elegan
xtonousou
Ada perbedaan besar antara __file__dan sys.argv[0], lihat stackoverflow.com/questions/5851588/...
Maksym Ganenko
8

Argumen pertama dalam sys akan menjadi nama file saat ini sehingga ini akan berfungsi

   import sys
   print sys.argv[0] # will print the file name
Charlie OConor
sumber
7

Jika Anda melakukan impor yang tidak biasa (mis., Ini adalah file opsi), cobalah:

import inspect
print (inspect.getfile(inspect.currentframe()))

Perhatikan bahwa ini akan mengembalikan path absolut ke file.

Gajendra D Ambi
sumber
3

kita dapat mencoba ini untuk mendapatkan nama skrip saat ini tanpa ekstensi.

import os

script_name = os.path.splitext(os.path.basename(__file__))[0]
Krishn Singh
sumber
2

Karena OP meminta nama file skrip saat ini saya lebih suka

import os
os.path.split(sys.argv[0])[1]
PeterXX
sumber
1

semua jawaban itu bagus, tetapi memiliki beberapa masalah Anda mungkin tidak melihat pada pandangan pertama.

mari tentukan apa yang kita inginkan - kita ingin nama skrip yang dieksekusi, bukan nama modul saat ini - jadi __file__hanya akan berfungsi jika digunakan pada skrip yang dieksekusi, bukan dalam modul yang diimpor. sys.argvjuga dipertanyakan - bagaimana jika program Anda dipanggil oleh pytest? atau pydoc runner? atau apakah itu disebut oleh uwsgi?

dan - ada metode ketiga untuk mendapatkan nama skrip, saya belum melihat dalam jawaban - Anda dapat memeriksa tumpukan.

Masalah lain adalah, bahwa Anda (atau program lain) dapat mengutak-atik sys.argvdan__main__.__file__ - mungkin ada, mungkin tidak. Mungkin valid, atau tidak. Setidaknya Anda dapat memeriksa apakah skrip (hasil yang diinginkan) ada!

bitranox perpustakaan saya / lib_programname di github melakukan hal itu:

  • periksa apakah __main__ada
  • periksa apakah __main__.__file__ada
  • memang memberikan __main__.__file__hasil yang valid (apakah skrip itu ada?)
  • jika tidak: periksa sys.argv:
  • apakah ada pytest, docrunner, dll di sys.argv? -> jika ya, abaikan itu
  • bisakah kita mendapatkan hasil yang valid di sini?
  • jika tidak: periksa tumpukan dan dapatkan hasilnya dari sana
  • jika juga stack tidak memberikan hasil yang valid, maka lemparkan Exception.

dengan cara itu, solusi saya bekerja sejauh ini dengan setup.py test, uwsgi, pytest, pycharm pytest, pycharm docrunner (doctest), dreampie,eclipse

ada juga artikel blog yang bagus tentang masalah itu dari Dough Hellman, "Menentukan Nama Proses dari Python"

bitranox
sumber
0

Solusi cepat kotor saya:

__file__.split('/')[-1:][0]
E.Big
sumber
2
Lebih baik digunakan os.pathuntuk membagi nama file
Maksym Ganenko
0

Pada Python 3.5, Anda cukup melakukan:

from pathlib import Path
Path(__file__).stem

Lihat lebih lanjut di sini: https://docs.python.org/3.5/library/pathlib.html#pathlib.PurePath.stem

Sebagai contoh, saya memiliki file di bawah direktori pengguna saya bernama test.pydengan ini di dalam:

from pathlib import Path

print(Path(__file__).stem)
print(__file__)

menjalankan output ini:

>>> python3.6 test.py
test
test.py
elad perak
sumber