รับชื่อของสคริปต์ปัจจุบันใน Python


407

ฉันพยายามรับชื่อของสคริปต์ Python ที่กำลังทำงานอยู่

ฉันมีสคริปต์ชื่อfoo.pyและฉันต้องการทำสิ่งนี้เพื่อรับชื่อสคริปต์:

print Scriptname

คำตอบ:


620

คุณสามารถใช้__file__เพื่อรับชื่อของไฟล์ปัจจุบัน เมื่อใช้ในโมดูลหลักนี่คือชื่อของสคริปต์ที่ถูกเรียกใช้ในตอนแรก

หากคุณต้องการที่จะละเว้นส่วนไดเรกทอรี (ซึ่งอาจจะเป็นปัจจุบัน) os.path.basename(__file__)คุณสามารถใช้


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

20
@sdaau: __file__ไม่ได้กำหนดไว้ในล่ามแบบโต้ตอบเพราะมันไม่มีความหมาย มันถูกตั้งค่าโดยการใช้งานการนำเข้าดังนั้นหากคุณใช้กลไกการนำเข้าที่ไม่ได้มาตรฐานก็อาจถูกยกเลิกการตั้งค่า
Sven Marnach

8
อย่างน้อยสำหรับ Python 2.7 ฉันเชื่อว่าสิ่งimport osนี้เป็นสิ่งจำเป็นสำหรับการทำงาน ฉันจะเพิ่มลงในคำตอบ
Nick Chammas

14
@ cdunn2001: import osและimport os.pathเทียบเท่าอย่างสมบูรณ์
Sven Marnach

2
@ sven-marnach: โอ้ใช่แล้ว ฉันทำผิดไปหลายปีแล้ว!
cdunn2001

136
import sys
print sys.argv[0]

นี้จะพิมพ์foo.pyสำหรับpython foo.py, dir/foo.pyสำหรับpython dir/foo.pyฯลฯ pythonมันอาร์กิวเมนต์แรก (โปรดทราบว่าหลังจาก py2exe จะเป็นfoo.exeเช่นนั้น)


33
@DenisMalinovsky: define "ไม่ทำงาน" ถ้าคุณเรียกpython linkfile.pyที่linkfile.pyเป็น symlink ไปrealfile.py, sys.argv[0]จะเป็น'linkfile.py'ซึ่งอาจหรือไม่อาจจะเป็นสิ่งที่คุณต้องการ; เป็นที่แน่นอนสิ่งที่ผมคาดหวัง __file__เหมือนกัน: linkfile.pyมันจะเป็น หากคุณต้องการที่จะหา'realfile.py'จากลอง'linkfile.py' os.path.realpath('linkfile.py')
Chris Morgan

6
+1 เนื่องจากเป็น (ก) ตัวเรียงลำดับขนาดเล็กและ (ข) จะยังคงทำงานในโมดูล (โดยที่ตัวแปรไฟล์จะเป็นไฟล์โมดูลไม่ใช่ตัวประมวลผล)
เบิร์ต

คำตอบนี้ดีเพราะใช้งานได้ใน IDLE ด้วย เพื่อทราบเพียงชื่อไฟล์คุณสามารถเขียน os.path.basename (sys.argv [0])
Steven Bluen

ที่สำคัญกว่านี้ไม่สามารถใช้งานได้ยกเว้นภายในไฟล์หลัก อย่าใช้สิ่งนี้ใช้__file__แทน
Apollys สนับสนุนโมนิก้า

อะไร!!! คุณลองสิ่งนี้หรือไม่? ตรงข้ามเป็นจริง ผู้ถามถามชื่อของสคริปต์ไพ ธ อนที่กำลังเรียกใช้ไม่ใช่ไฟล์ไพ ธ อนซึ่งกำลังดำเนินการอยู่ในปัจจุบัน ลองนึกภาพว่าคุณมีสคริปต์ที่เมื่อเกิดข้อผิดพลาดให้พิมพ์ชื่อสคริปต์พร้อมกับอาร์กิวเมนต์ที่อนุญาต คุณใส่มันลงในฟังก์ชั่นโดยใช้หนึ่งในสองเทคนิคนี้ ในบางจุดคุณตัดสินใจย้ายฟังก์ชันไปยังไลบรารีภายนอก คุณต้องการที่จะพิมพ์ชื่อของสคริปต์หลักที่ทำงานอยู่หรือชื่อของไฟล์ไลบรารีที่กำลังทำงานอยู่หรือไม่?
John Deighan

71

เพื่อประโยชน์ของความสมบูรณ์ฉันคิดว่ามันคุ้มค่าที่จะสรุปผลลัพธ์ที่เป็นไปได้ที่หลากหลายและจัดหาการอ้างอิงสำหรับพฤติกรรมที่แน่นอนของแต่ละ

  • __file__เป็นไฟล์ที่กำลังดำเนินการตามรายละเอียดในเอกสารอย่างเป็นทางการ :

    __file__เป็นชื่อพา ธ ของไฟล์ที่โมดูลถูกโหลดถ้ามันถูกโหลดจากไฟล์ __file__แอตทริบิวต์อาจจะขาดหายไปสำหรับบางประเภทของโมดูลเช่นCโมดูลที่มีการเชื่อมโยงแบบคงที่เข้าล่าม; สำหรับโมดูลส่วนขยายที่โหลดแบบไดนามิกจากไลบรารีที่แชร์จะเป็นชื่อพา ธ ของไฟล์ไลบรารีที่แชร์

    จาก Python3.4เป็นต้นไปต่อปัญหา 18416 , __file__อยู่เสมอเส้นทางแน่นอนเว้นแต่ไฟล์ในขณะนี้การดำเนินการเป็นสคริปต์ที่ได้รับการดำเนินการโดยตรง (ไม่ผ่านล่ามที่มี-mตัวเลือกบรรทัดคำสั่ง) โดยใช้เส้นทางสัมพัทธ์

  • __main__.__file__(ต้องนำเข้า__main__) เพียงแค่เข้าถึง__file__แอตทริบิวต์ดังกล่าวของโมดูลหลักเช่นของสคริปต์ที่ถูกเรียกจากบรรทัดคำสั่ง

  • sys.argv[0](ต้องนำเข้าsys) เป็นชื่อสคริปต์ที่ถูกเรียกใช้จากบรรทัดคำสั่งและอาจเป็นพา ธ สัมบูรณ์ตามรายละเอียดในเอกสารประกอบอย่างเป็นทางการ :

    argv[0]เป็นชื่อสคริปต์ (ขึ้นอยู่กับระบบปฏิบัติการไม่ว่าจะเป็นชื่อพา ธ แบบเต็มหรือไม่ก็ตาม) ถ้าคำสั่งที่ถูกดำเนินการโดยใช้-cตัวเลือกบรรทัดคำสั่งเพื่อล่ามถูกตั้งค่าเป็นสตริงargv[0] '-c'หากไม่มีการส่งชื่อสคริปต์ไปยังตัวแปล Python argv[0]จะเป็นสตริงว่าง

    ตามที่ระบุไว้ในคำตอบของคำถามนี้อีก , งูหลามสคริปต์ที่ถูกแปลงเป็นโปรแกรมปฏิบัติการแบบสแตนด์อะโลนผ่านเครื่องมือเช่นpy2exeหรือPyInstallerอาจไม่แสดงผลที่ต้องการเมื่อใช้วิธีนี้ (คือsys.argv[0]จะถือชื่อของปฏิบัติการมากกว่าชื่อ ของไฟล์Pythonหลักที่สามารถเรียกใช้งานได้)

  • หากไม่มีตัวเลือกใด ๆ ที่กล่าวมาใช้งานได้อาจเนื่องมาจากการดำเนินการนำเข้าที่ผิดปกติโมดูลตรวจสอบอาจพิสูจน์ว่ามีประโยชน์ โดยเฉพาะอย่างยิ่งการกล่าวอ้างinspect.getfile(...)ในinspect.currentframe()สามารถทำงานได้แม้ภายหลังจะกลับมาNoneเมื่อใช้ในการดำเนินการโดยไม่ต้องหลามกองกรอบ


การจัดการลิงก์สัญลักษณ์

หากสคริปต์ปัจจุบันเป็นลิงก์สัญลักษณ์แล้วทั้งหมดข้างต้นจะกลับเส้นทางของลิงก์สัญลักษณ์มากกว่าเส้นทางของไฟล์จริงและos.path.realpath(...)ควรจะเรียกใช้เพื่อแยกหลัง


การปรับแต่งเพิ่มเติมที่แยกชื่อไฟล์จริง

os.path.basename(...)อาจถูกเรียกใช้ในข้อใดข้อหนึ่งข้างต้นเพื่อแยกชื่อไฟล์จริงและos.path.splitext(...)อาจถูกเรียกใช้กับชื่อไฟล์จริงเพื่อตัดส่วนต่อท้ายดังเช่นในos.path.splitext(os.path.basename(...))อาจเรียกในชื่อไฟล์ที่เกิดขึ้นจริงในการที่จะตัดต่อท้ายเช่นเดียวกับใน

จากงูหลาม 3.4เป็นต้นไปต่อPEP 428ที่PurePathระดับของpathlibโมดูลอาจจะใช้เป็นอย่างดีในการใด ๆ ข้างต้น โดยเฉพาะpathlib.PurePath(...).nameสารสกัดจากชื่อไฟล์ที่เกิดขึ้นจริงและpathlib.PurePath(...).stemสารสกัดจากชื่อไฟล์ที่เกิดขึ้นจริงโดยไม่ต้องต่อท้าย


66

โปรดทราบว่า__file__จะให้ไฟล์ที่มีรหัสนี้ซึ่งสามารถนำเข้าและแตกต่างจากไฟล์หลักที่ถูกตีความ ในการรับไฟล์หลักสามารถใช้โมดูล__main__พิเศษได้:

import __main__ as main
print(main.__file__)

โปรดทราบว่าใช้__main__.__file__งานได้ใน Python 2.7 แต่ไม่ได้อยู่ใน 3.2 ดังนั้นใช้ไวยากรณ์ import-as ดังที่กล่าวมาข้างต้นเพื่อทำให้พกพาได้


สิ่งนี้ใช้ได้ในหลายกรณี แต่ไม่ใช่เมื่อฉันใช้rPythonแพ็คเกจจากRภาษา ต้องเป็นกรณีพิเศษที่ยากเกินกว่าจะรับมือได้
Leonid

แท้จริงแล้วแพ็คเกจ rPython ฝังตัวแปลภาษาไพ ธ อนซึ่งหมายความว่าไม่มีไฟล์ 'main' เหมือนเมื่อ python กำลังทำงานด้วยตัวมันเอง มันนำเข้า__main__ภายในเพื่อใช้ในการส่งผ่านตัวแปรระหว่างRและpythonดังนั้นจึงค่อนข้างง่ายที่จะตั้งไว้__main__.__file__ก่อนที่จะเรียกสิ่งอื่น แต่ฉันไม่แน่ใจว่าสิ่งที่จะเป็นค่าที่เหมาะสมในกรณีนี้
Perkins

42

คำตอบข้างต้นเป็นสิ่งที่ดี แต่ฉันพบวิธีนี้มีประสิทธิภาพมากขึ้นโดยใช้ผลลัพธ์ด้านบน
ซึ่งส่งผลให้ชื่อไฟล์สคริปต์จริงไม่ใช่เส้นทาง

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

1
ฉันชอบแยกส่วนขยายออกด้วยดังนั้นฉันจึงใช้: os.path.splitext (os.path.basename (sys.argv [0])) [0]
RufusVS

19

สำหรับเวอร์ชัน Python ที่ทันสมัย ​​(3.4+) Path(__file__).nameควรเป็นสำนวนที่มากกว่า นอกจากนี้ยังPath(__file__).stemให้ชื่อสคริปต์ที่ไม่มี.pyส่วนขยาย


NameError: ไม่ได้กำหนดชื่อ 'เส้นทาง'
RufusVS

5
คุณควรfrom pathlib import Pathก่อน
Emil Melnikov

"modern" หมายถึง Python 3.x หรือไม่
einpoklum

1
@einpoklum pathlibได้รับการแนะนำใน Python 3.4 ดังนั้นจึงควรเริ่มต้นจาก Python 3.4
Andrey Semakin


9

หมายเหตุ: หากคุณใช้ Python 3+ คุณควรใช้ฟังก์ชัน print () แทน

สมมติว่าชื่อไฟล์คือfoo.pyตัวอย่างด้านล่าง

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

หรือ

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

สำหรับขอบเขตอื่น ๆ ที่มีตัวอักษรมากขึ้นเช่นชื่อไฟล์ foo.pypy

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

หากคุณต้องการแยกจากเส้นทางที่แน่นอน

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

จะส่งออก foo


1
sys.argv [0] [: - 3] จะทำ
kon Psych

@konpsych นั้นดูสง่างามยิ่งขึ้น
xtonousou

มีความแตกต่างอย่างมากระหว่าง__file__และsys.argv[0]ดูstackoverflow.com/questions/5851588/…
Maksym Ganenko

8

อาร์กิวเมนต์แรกใน sys จะเป็นชื่อไฟล์ปัจจุบันดังนั้นสิ่งนี้จะทำงาน

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

7

หากคุณกำลังนำเข้าที่ผิดปกติ (เช่นเป็นไฟล์ตัวเลือก) ให้ลอง:

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

โปรดทราบว่านี่จะส่งคืนพา ธ สัมบูรณ์ไปยังไฟล์


3

เราสามารถทดลองใช้เพื่อรับชื่อสคริปต์ปัจจุบันโดยไม่มีส่วนขยาย

import os

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

2

เนื่องจาก OP ขอชื่อไฟล์สคริปต์ปัจจุบันที่ฉันต้องการ

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



0

คำตอบทั้งหมดนั้นยอดเยี่ยม แต่มีปัญหาบางอย่างคุณอาจไม่เห็นในการมองครั้งแรก

ให้กำหนดสิ่งที่เราต้องการ - เราต้องการชื่อของสคริปต์ที่ถูกเรียกใช้ไม่ใช่ชื่อของโมดูลปัจจุบัน - ดังนั้น__file__จะใช้งานได้ก็ต่อเมื่อมันถูกใช้ในสคริปต์ที่เรียกใช้งานไม่ใช่ในโมดูลที่นำเข้า sys.argvยังมีคำถามอยู่ - ถ้าโปรแกรมของคุณถูกเรียกโดย pytest? หรือรองชนะเลิศอันดับ pydoc? หรือถ้ามันถูกเรียกโดย uwsgi?

และ - มีวิธีที่สามในการรับชื่อสคริปต์ฉันไม่เห็นในคำตอบ - คุณสามารถตรวจสอบสแต็กได้

ปัญหาอีกประการหนึ่งคือคุณ (หรือโปรแกรมอื่น) สามารถยุ่งเกี่ยวกับsys.argvและ__main__.__file__ - อาจมีอยู่ก็อาจจะไม่ มันอาจจะถูกต้องหรือไม่ อย่างน้อยคุณสามารถตรวจสอบว่ามีสคริปต์ (ผลลัพธ์ที่ต้องการ) อยู่หรือไม่!

bitranox / lib_programname ห้องสมุดของฉันที่ github ทำอย่างนั้น:

  • ตรวจสอบว่า __main__มีอยู่
  • ตรวจสอบว่า __main__.__file__มีอยู่
  • ไม่ให้ __main__.__file__ผลลัพธ์ที่ถูกต้อง (สคริปต์นั้นมีอยู่จริงหรือไม่)
  • ถ้าไม่ใช่: ตรวจสอบ sys.argv:
  • มี pytest, docrunner และอื่น ๆ ใน sys.argv หรือไม่? -> ถ้าใช่เพิกเฉย
  • เราจะได้รับผลลัพธ์ที่ถูกต้องที่นี่?
  • ถ้าไม่ใช่: ตรวจสอบสแต็กและรับผลลัพธ์จากที่นั่น
  • ถ้าสแต็กไม่ให้ผลลัพธ์ที่ถูกต้องให้โยน Exception

โดยวิธีการที่แก้ปัญหาของฉันคือการทำงานเพื่อให้ห่างไกลกับsetup.py test, uwsgi, pytest, pycharm pytest, pycharm docrunner (doctest), dreampie,eclipse

นอกจากนี้ยังมีบทความบล็อกที่ดีเกี่ยวกับปัญหาดังกล่าวจาก Dough Hellman "การกำหนดชื่อของกระบวนการจาก Python"


0

จาก Python 3.5 คุณสามารถทำสิ่งต่อไปนี้

from pathlib import Path
Path(__file__).stem

ดูเพิ่มเติมได้ที่นี่: https://docs.python.org/3.5/library/pathlib.html#pathlib.PurePath.stem

ตัวอย่างเช่นฉันมีไฟล์ภายใต้ไดเรกทอรีผู้ใช้ของฉันที่test.pyมีชื่ออยู่ข้างใน:

from pathlib import Path

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

เรียกใช้ผลลัพธ์นี้:

>>> python3.6 test.py
test
test.py
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.