Nhận tên của tập lệnh hiện tại trong Python


407

Tôi đang cố gắng để có được tên của tập lệnh Python hiện đang chạy.

Tôi có một tập lệnh được gọi foo.pyvà tôi muốn làm một cái gì đó như thế này để có được tên tập lệnh:

print Scriptname

Câu trả lời:


620

Bạn có thể sử dụng __file__để có được tên của tập tin hiện tại. Khi được sử dụng trong mô-đun chính, đây là tên của tập lệnh ban đầu được gọi.

Nếu bạn muốn bỏ qua phần thư mục (có thể có mặt), bạn có thể sử dụng os.path.basename(__file__).


15
Python 3.2: " Exception NameError: NameError("global name '__file__' is not defined",)"
sdaau

20
@sdaau: __file__không được định nghĩa trong trình thông dịch tương tác, vì nó vô nghĩa ở đó. Nó được thiết lập bởi việc thực hiện nhập, vì vậy nếu bạn sử dụng cơ chế nhập không chuẩn thì nó cũng có thể không được đặt.
Sven Marnach

8
Ít nhất là đối với Python 2.7, tôi tin rằng import oscần phải có để nó hoạt động. Tôi sẽ thêm điều này vào câu trả lời.
Nick Chammas

14
@ cdunn2001: import osimport os.pathhoàn toàn tương đương.
Sven Marnach

2
@ sven-marnach: Ồ, bạn nói đúng . Tôi đã làm điều đó sai trong nhiều năm!
cdunn2001

136
import sys
print sys.argv[0]

Điều này sẽ in foo.pycho python foo.py, dir/foo.pycho python dir/foo.py, vv Đó là đối số đầu tiên python. (Lưu ý rằng sau py2exe thì sẽ như vậy foo.exe.)


33
@DenisMalinovsky: định nghĩa "sẽ không hoạt động". Nếu bạn gọi python linkfile.py, nơi linkfile.pymột symlink đến realfile.py, sys.argv[0]sẽ là 'linkfile.py', có thể hoặc không thể là những gì bạn muốn; nó chắc chắn là những gì tôi mong đợi . __file__là như nhau: nó sẽ được linkfile.py. Nếu bạn muốn tìm 'realfile.py'từ 'linkfile.py', hãy thử os.path.realpath('linkfile.py').
Chris Morgan

6
+1 vì nó (a) gọn gàng hơn một chút và (b) vẫn sẽ hoạt động trong mô-đun (trong đó biến tệp sẽ là tệp mô-đun, không phải là tệp thực thi).
robert

Câu trả lời này rất hay vì nó cũng hoạt động trong IDLE. Lưu ý, để chỉ lấy tên tệp, bạn có thể viết os.path.basename (sys.argv [0])
Steven Bluen

Quan trọng hơn, điều này không hoạt động ngoại trừ từ bên trong tệp chính. Không sử dụng cái này, sử dụng __file__thay thế.
Apollys hỗ trợ Monica

GÌ!!! Bạn thậm chí đã thử điều này? Chính xác thì ngược lại. Người hỏi đã hỏi tên của kịch bản python đang chạy - không phải tệp python hiện đang thực thi. Hãy tưởng tượng rằng bạn có một tập lệnh mà khi xảy ra lỗi, sẽ in tên tập lệnh cùng với các đối số được phép. Bạn đặt nó trong một hàm, sử dụng một trong 2 kỹ thuật này. Tại một số điểm, bạn quyết định chuyển chức năng sang một thư viện bên ngoài. Bạn có muốn in tên của tập lệnh chính đang chạy hoặc tên của tệp thư viện đang thực thi không?
John Deighan

71

Để hoàn thiện, tôi nghĩ rằng sẽ rất đáng để tóm tắt các kết quả có thể khác nhau và cung cấp tài liệu tham khảo cho hành vi chính xác của từng:

  • __file__là tập tin hiện đang thực thi, như chi tiết trong tài liệu chính thức :

    __file__là tên đường dẫn của tệp mà mô-đun được tải, nếu nó được tải từ một tệp. Các __file__thuộc tính có thể thiếu cho một số loại mô-đun, chẳng hạn như C module được liên kết tĩnh thành người phiên dịch; đối với các mô-đun mở rộng được tải động từ thư viện dùng chung, đó là tên đường dẫn của tệp thư viện dùng chung.

    Từ Python3.4 trở đi, mỗi vấn đề 18416 , __file__luôn là một đường dẫn tuyệt đối, trừ khi tệp hiện đang thực thi là một tập lệnh được thực thi trực tiếp (không thông qua trình thông dịch với -mtùy chọn dòng lệnh) bằng cách sử dụng đường dẫn tương đối.

  • __main__.__file__(yêu cầu nhập __main__) chỉ cần truy cập vào __file__thuộc tính đã nói ở trên của mô-đun chính , ví dụ: tập lệnh được gọi từ dòng lệnh.

  • sys.argv[0](yêu cầu nhập sys) là tên tập lệnh được gọi từ dòng lệnh và có thể là một đường dẫn tuyệt đối, như được nêu chi tiết trong tài liệu chính thức :

    argv[0]là tên tập lệnh (nó phụ thuộc vào hệ điều hành cho dù đây có phải là tên đường dẫn đầy đủ hay không). Nếu lệnh được thực thi bằng -ctùy chọn dòng lệnh cho trình thông dịch, argv[0]được đặt thành chuỗi '-c'. Nếu không có tên tập lệnh nào được chuyển đến trình thông dịch Python, thì đó argv[0]là chuỗi rỗng.

    Như đã đề cập trong câu trả lời khác cho câu hỏi này , các tập lệnh Python được chuyển đổi thành các chương trình thực thi độc lập thông qua các công cụ như py2exe hoặc PyInstaller có thể không hiển thị kết quả mong muốn khi sử dụng phương pháp này (nghĩa là sys.argv[0]sẽ giữ tên của tệp thực thi thay vì tên của tệp Python chính trong tệp thực thi đó).

  • Nếu không có tùy chọn nào nói trên có vẻ hoạt động, có thể do hoạt động nhập không đều, mô-đun kiểm tra có thể hữu ích. Cụ thể, việc gọi inspect.getfile(...)vào inspect.currentframe()có thể hoạt động, mặc dù cái sau sẽ trở lạiNone khi chạy trong một triển khai không có khung ngăn xếp Python .


Xử lý các liên kết tượng trưng

Nếu tập lệnh hiện tại là một liên kết tượng trưng, ​​thì tất cả các đoạn trên sẽ trả về đường dẫn của liên kết tượng trưng thay vì đường dẫn của tệp thực và os.path.realpath(...)nên được gọi để trích xuất đoạn sau.


Thao tác thêm trích xuất tên tệp thực tế

os.path.basename(...)có thể được gọi trên bất kỳ mục nào ở trên để trích xuất tên tệp thực tế và os.path.splitext(...)có thể được gọi trên tên tệp thực tế để cắt bớt hậu tố của nó, như trongos.path.splitext(os.path.basename(...)) .

Từ Python 3.4 trở đi, trên mỗi PEP 428 , PurePathlớp của pathlibmô-đun cũng có thể được sử dụng cho bất kỳ mục nào ở trên. Cụ thể, pathlib.PurePath(...).nametrích xuất tên tệp thực tế và pathlib.PurePath(...).stemtrích xuất tên tệp thực tế mà không có hậu tố của nó.


66

Lưu ý rằng __file__sẽ cung cấp cho tệp nơi mã này cư trú, có thể được nhập và khác với tệp chính đang được diễn giải. Để lấy tệp chính, mô-đun __main__ đặc biệt có thể được sử dụng:

import __main__ as main
print(main.__file__)

Lưu ý rằng nó __main__.__file__hoạt động trong Python 2.7 nhưng không phải trong 3.2, vì vậy hãy sử dụng cú pháp nhập như dưới đây để làm cho nó di động.


Điều này hoạt động trong nhiều trường hợp nhưng không phải khi tôi đang sử dụng rPythongói từ Rngôn ngữ. Đó phải là một trường hợp đặc biệt mà quá khó để xử lý.
Leonid

Thật vậy, gói rPython nhúng trình thông dịch python, có nghĩa là không có tệp 'chính' như khi python tự chạy (bạn sẽ tìm thấy hành vi tương tự bất cứ khi nào python được nhúng). Nó nhập __main__nội bộ, để sử dụng trong việc chuyển các biến giữa Rpythonvì vậy sẽ tương đối dễ dàng để đặt nó __main__.__file__trước khi gọi bất cứ thứ gì khác, nhưng tôi thậm chí không chắc giá trị nào phù hợp trong trường hợp này.
Perkins

42

Các câu trả lời trên là tốt. Nhưng tôi thấy phương pháp này hiệu quả hơn bằng cách sử dụng các kết quả trên.
Điều này dẫn đến tên tập tin thực tế không phải là một đường dẫn.

import sys    
import os    
file_name =  os.path.basename(sys.argv[0])

1
Tôi cũng muốn tách phần mở rộng, vì vậy tôi sử dụng: os.path.splitext (os.path.basename (sys.argv [0])) [0]
RufusVS 23/07/18

19

Đối với các phiên bản Python hiện đại (3,4+), Path(__file__).namenên có nhiều thành ngữ hơn. Ngoài ra, Path(__file__).stemcung cấp cho bạn tên tập lệnh mà không cần .pyphần mở rộng.


TênError: tên 'Đường dẫn' không được xác định
RufusVS

5
Bạn nên from pathlib import Pathđầu tiên.
Emil Melnikov

"Hiện đại" có nghĩa là Python 3.x?
einpoklum

1
@einpoklum pathlibđược giới thiệu trong Python 3.4, vì vậy nó sẽ hoạt động bắt đầu từ Python 3.4.
Andrey Semakin


9

Lưu ý: Nếu bạn đang sử dụng Python 3+, thì bạn nên sử dụng hàm print ()

Giả sử tên tệp là foo.py, đoạn dưới đây

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

hoặc là

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

Đối với các phạm vi khác có nhiều ký tự hơn, ví dụ như tên tệp foo.pypy

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

Nếu bạn muốn trích xuất từ ​​một đường dẫn tuyệt đối

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

sẽ xuất foo


1
sys.argv [0] [: - 3] sẽ làm
tâm lý

@konpsych thanh lịch hơn
xtonousou

Có sự khác biệt lớn giữa __file__sys.argv[0], xem stackoverflow.com/questions/5851588/ từ
Maksym Ganenko

8

Đối số đầu tiên trong sys sẽ là tên tệp hiện tại để nó hoạt động

   import sys
   print sys.argv[0] # will print the file name

7

Nếu bạn đang thực hiện nhập bất thường (ví dụ: đó là tệp tùy chọn), hãy thử:

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

Lưu ý rằng điều này sẽ trả về đường dẫn tuyệt đối đến tập tin.


3

chúng ta có thể thử điều này để có được tên tập lệnh hiện tại mà không cần gia hạn.

import os

script_name = os.path.splitext(os.path.basename(__file__))[0]

2

Vì OP đã hỏi tên tập tin tập lệnh hiện tại nên tôi thích

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

1

tất cả những câu trả lời là tuyệt vời, nhưng có một số vấn đề Bạn có thể không nhìn thấy ngay từ cái nhìn đầu tiên.

cho phép xác định những gì chúng ta muốn - chúng ta muốn tên của tập lệnh đã được thực thi, không phải tên của mô-đun hiện tại - vì vậy __file__sẽ chỉ hoạt động nếu nó được sử dụng trong tập lệnh đã thực hiện, không phải trong mô-đun đã nhập. sys.argvcũng có vấn đề - nếu chương trình của bạn được gọi bởi pytest thì sao? hay người chạy pydoc? hoặc nếu nó được gọi bởi uwsgi?

và - có một phương pháp thứ ba để có được tên tập lệnh, tôi chưa thấy trong các câu trả lời - Bạn có thể kiểm tra ngăn xếp.

Một vấn đề khác là, Bạn (hoặc một số chương trình khác) có thể can thiệp xung quanh sys.argv__main__.__file__ - nó có thể có mặt, nó có thể không. Nó có thể hợp lệ, hoặc không. Ít nhất Bạn có thể kiểm tra xem tập lệnh (kết quả mong muốn) có tồn tại không!

thư viện của tôi bitranox / lib_programname tại github thực hiện chính xác điều đó:

  • kiểm tra nếu __main__
  • kiểm tra nếu __main__.__file__
  • không cho __main__.__file__kết quả hợp lệ (tập lệnh đó có tồn tại không?)
  • nếu không: kiểm tra sys.argv:
  • Có pytest, docrunner, vv trong sys.argv không? -> nếu có, bỏ qua điều đó
  • chúng ta có thể nhận được một kết quả hợp lệ ở đây không?
  • nếu không: kiểm tra ngăn xếp và nhận kết quả từ đó có thể
  • nếu ngăn xếp cũng không cho kết quả hợp lệ, thì hãy ném Ngoại lệ.

bằng cách đó, giải pháp của tôi đang làm việc cho đến nay với setup.py test, uwsgi, pytest, pycharm pytest, pycharm docrunner (doctest), dreampie,eclipse

cũng có một bài viết blog hay về vấn đề đó từ Dough Hellman, "Xác định tên của một quá trình từ Python"


0

Giải pháp bẩn nhanh của tôi:

__file__.split('/')[-1:][0]

2
Sử dụng tốt hơn os.pathđể phân chia tên tệp
Maksym Ganenko


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.