ฉันพยายามรับชื่อของสคริปต์ Python ที่กำลังทำงานอยู่
ฉันมีสคริปต์ชื่อfoo.py
และฉันต้องการทำสิ่งนี้เพื่อรับชื่อสคริปต์:
print Scriptname
ฉันพยายามรับชื่อของสคริปต์ Python ที่กำลังทำงานอยู่
ฉันมีสคริปต์ชื่อfoo.py
และฉันต้องการทำสิ่งนี้เพื่อรับชื่อสคริปต์:
print Scriptname
คำตอบ:
คุณสามารถใช้__file__
เพื่อรับชื่อของไฟล์ปัจจุบัน เมื่อใช้ในโมดูลหลักนี่คือชื่อของสคริปต์ที่ถูกเรียกใช้ในตอนแรก
หากคุณต้องการที่จะละเว้นส่วนไดเรกทอรี (ซึ่งอาจจะเป็นปัจจุบัน) os.path.basename(__file__)
คุณสามารถใช้
__file__
ไม่ได้กำหนดไว้ในล่ามแบบโต้ตอบเพราะมันไม่มีความหมาย มันถูกตั้งค่าโดยการใช้งานการนำเข้าดังนั้นหากคุณใช้กลไกการนำเข้าที่ไม่ได้มาตรฐานก็อาจถูกยกเลิกการตั้งค่า
import os
นี้เป็นสิ่งจำเป็นสำหรับการทำงาน ฉันจะเพิ่มลงในคำตอบ
import os
และimport os.path
เทียบเท่าอย่างสมบูรณ์
import sys
print sys.argv[0]
นี้จะพิมพ์foo.py
สำหรับpython foo.py
, dir/foo.py
สำหรับpython dir/foo.py
ฯลฯ python
มันอาร์กิวเมนต์แรก (โปรดทราบว่าหลังจาก py2exe จะเป็นfoo.exe
เช่นนั้น)
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')
__file__
แทน
เพื่อประโยชน์ของความสมบูรณ์ฉันคิดว่ามันคุ้มค่าที่จะสรุปผลลัพธ์ที่เป็นไปได้ที่หลากหลายและจัดหาการอ้างอิงสำหรับพฤติกรรมที่แน่นอนของแต่ละ
__file__
เป็นไฟล์ที่กำลังดำเนินการตามรายละเอียดในเอกสารอย่างเป็นทางการ :
__file__
เป็นชื่อพา ธ ของไฟล์ที่โมดูลถูกโหลดถ้ามันถูกโหลดจากไฟล์__file__
แอตทริบิวต์อาจจะขาดหายไปสำหรับบางประเภทของโมดูลเช่นCโมดูลที่มีการเชื่อมโยงแบบคงที่เข้าล่าม; สำหรับโมดูลส่วนขยายที่โหลดแบบไดนามิกจากไลบรารีที่แชร์จะเป็นชื่อพา ธ ของไฟล์ไลบรารีที่แชร์
จาก Python3.4เป็นต้นไปต่อปัญหา 18416 , __file__
อยู่เสมอเส้นทางแน่นอนเว้นแต่ไฟล์ในขณะนี้การดำเนินการเป็นสคริปต์ที่ได้รับการดำเนินการโดยตรง (ไม่ผ่านล่ามที่มี-m
ตัวเลือกบรรทัดคำสั่ง) โดยใช้เส้นทางสัมพัทธ์
__main__.__file__
(ต้องนำเข้า__main__
) เพียงแค่เข้าถึง__file__
แอตทริบิวต์ดังกล่าวของโมดูลหลักเช่นของสคริปต์ที่ถูกเรียกจากบรรทัดคำสั่ง
sys.argv[0]
(ต้องนำเข้าsys
) เป็นชื่อสคริปต์ที่ถูกเรียกใช้จากบรรทัดคำสั่งและอาจเป็นพา ธ สัมบูรณ์ตามรายละเอียดในเอกสารประกอบอย่างเป็นทางการ :
argv[0]
เป็นชื่อสคริปต์ (ขึ้นอยู่กับระบบปฏิบัติการไม่ว่าจะเป็นชื่อพา ธ แบบเต็มหรือไม่ก็ตาม) ถ้าคำสั่งที่ถูกดำเนินการโดยใช้-c
ตัวเลือกบรรทัดคำสั่งเพื่อล่ามถูกตั้งค่าเป็นสตริงargv[0]
'-c'
หากไม่มีการส่งชื่อสคริปต์ไปยังตัวแปล Pythonargv[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
สารสกัดจากชื่อไฟล์ที่เกิดขึ้นจริงโดยไม่ต้องต่อท้าย
โปรดทราบว่า__file__
จะให้ไฟล์ที่มีรหัสนี้ซึ่งสามารถนำเข้าและแตกต่างจากไฟล์หลักที่ถูกตีความ ในการรับไฟล์หลักสามารถใช้โมดูล__main__พิเศษได้:
import __main__ as main
print(main.__file__)
โปรดทราบว่าใช้__main__.__file__
งานได้ใน Python 2.7 แต่ไม่ได้อยู่ใน 3.2 ดังนั้นใช้ไวยากรณ์ import-as ดังที่กล่าวมาข้างต้นเพื่อทำให้พกพาได้
rPython
แพ็คเกจจากR
ภาษา ต้องเป็นกรณีพิเศษที่ยากเกินกว่าจะรับมือได้
__main__
ภายในเพื่อใช้ในการส่งผ่านตัวแปรระหว่างR
และpython
ดังนั้นจึงค่อนข้างง่ายที่จะตั้งไว้__main__.__file__
ก่อนที่จะเรียกสิ่งอื่น แต่ฉันไม่แน่ใจว่าสิ่งที่จะเป็นค่าที่เหมาะสมในกรณีนี้
คำตอบข้างต้นเป็นสิ่งที่ดี แต่ฉันพบวิธีนี้มีประสิทธิภาพมากขึ้นโดยใช้ผลลัพธ์ด้านบน
ซึ่งส่งผลให้ชื่อไฟล์สคริปต์จริงไม่ใช่เส้นทาง
import sys
import os
file_name = os.path.basename(sys.argv[0])
สำหรับเวอร์ชัน Python ที่ทันสมัย (3.4+) Path(__file__).name
ควรเป็นสำนวนที่มากกว่า นอกจากนี้ยังPath(__file__).stem
ให้ชื่อสคริปต์ที่ไม่มี.py
ส่วนขยาย
from pathlib import Path
ก่อน
pathlib
ได้รับการแนะนำใน Python 3.4 ดังนั้นจึงควรเริ่มต้นจาก Python 3.4
ลองสิ่งนี้:
print __file__
สมมติว่าชื่อไฟล์คือ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
อาร์กิวเมนต์แรกใน sys จะเป็นชื่อไฟล์ปัจจุบันดังนั้นสิ่งนี้จะทำงาน
import sys
print sys.argv[0] # will print the file name
หากคุณกำลังนำเข้าที่ผิดปกติ (เช่นเป็นไฟล์ตัวเลือก) ให้ลอง:
import inspect
print (inspect.getfile(inspect.currentframe()))
โปรดทราบว่านี่จะส่งคืนพา ธ สัมบูรณ์ไปยังไฟล์
เราสามารถทดลองใช้เพื่อรับชื่อสคริปต์ปัจจุบันโดยไม่มีส่วนขยาย
import os
script_name = os.path.splitext(os.path.basename(__file__))[0]
เนื่องจาก OP ขอชื่อไฟล์สคริปต์ปัจจุบันที่ฉันต้องการ
import os
os.path.split(sys.argv[0])[1]
ทางออกที่สกปรกเร็วของฉัน:
__file__.split('/')[-1:][0]
os.path
เพื่อแยกชื่อไฟล์
os.path.abspath(__file__)
จะให้เส้นทางที่แน่นอน ( relpath()
เช่นกัน)
sys.argv[-1]
จะให้เส้นทางสัมพัทธ์กับคุณ
คำตอบทั้งหมดนั้นยอดเยี่ยม แต่มีปัญหาบางอย่างคุณอาจไม่เห็นในการมองครั้งแรก
ให้กำหนดสิ่งที่เราต้องการ - เราต้องการชื่อของสคริปต์ที่ถูกเรียกใช้ไม่ใช่ชื่อของโมดูลปัจจุบัน - ดังนั้น__file__
จะใช้งานได้ก็ต่อเมื่อมันถูกใช้ในสคริปต์ที่เรียกใช้งานไม่ใช่ในโมดูลที่นำเข้า
sys.argv
ยังมีคำถามอยู่ - ถ้าโปรแกรมของคุณถูกเรียกโดย pytest? หรือรองชนะเลิศอันดับ pydoc? หรือถ้ามันถูกเรียกโดย uwsgi?
และ - มีวิธีที่สามในการรับชื่อสคริปต์ฉันไม่เห็นในคำตอบ - คุณสามารถตรวจสอบสแต็กได้
ปัญหาอีกประการหนึ่งคือคุณ (หรือโปรแกรมอื่น) สามารถยุ่งเกี่ยวกับsys.argv
และ__main__.__file__
- อาจมีอยู่ก็อาจจะไม่ มันอาจจะถูกต้องหรือไม่ อย่างน้อยคุณสามารถตรวจสอบว่ามีสคริปต์ (ผลลัพธ์ที่ต้องการ) อยู่หรือไม่!
bitranox / lib_programname ห้องสมุดของฉันที่ github ทำอย่างนั้น:
__main__
มีอยู่__main__.__file__
มีอยู่__main__.__file__
ผลลัพธ์ที่ถูกต้อง (สคริปต์นั้นมีอยู่จริงหรือไม่)โดยวิธีการที่แก้ปัญหาของฉันคือการทำงานเพื่อให้ห่างไกลกับsetup.py test
, uwsgi
, pytest
, pycharm pytest
, pycharm docrunner (doctest)
, dreampie
,eclipse
นอกจากนี้ยังมีบทความบล็อกที่ดีเกี่ยวกับปัญหาดังกล่าวจาก Dough Hellman "การกำหนดชื่อของกระบวนการจาก Python"
จาก 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
Exception NameError: NameError("global name '__file__' is not defined",)
"