รับตำแหน่ง (เส้นทาง) ของไฟล์ที่ทำงานอยู่ใน Python: __file__

ธุรกิจ

ในการรับตำแหน่ง (เส้นทาง) ของไฟล์สคริปต์ที่ทำงานอยู่ใน Python ให้ใช้ __file__ ซึ่งมีประโยชน์สำหรับการโหลดไฟล์อื่นๆ ตามตำแหน่งของไฟล์ที่รันอยู่

มากถึง Python 3.8 __file__ ส่งคืนเส้นทางที่ระบุเมื่อดำเนินการคำสั่ง python (หรือคำสั่ง python3 ในบางสภาพแวดล้อม) หากระบุพาธสัมพัทธ์ เส้นทางสัมพัทธ์จะถูกส่งคืน หากระบุพาธสัมบูรณ์ เส้นทางสัมบูรณ์จะถูกส่งคืน

ใน Python 3.9 และใหม่กว่า เส้นทางสัมบูรณ์จะถูกส่งกลับโดยไม่คำนึงถึงเส้นทางที่ระบุที่รันไทม์

เนื้อหาต่อไปนี้จะอธิบาย

  • os.getcwd(),__file__
  • รับชื่อไฟล์และชื่อไดเร็กทอรีของไฟล์ที่กำลังดำเนินการอยู่
  • รับเส้นทางที่แน่นอนของไฟล์ที่กำลังดำเนินการ
  • อ่านไฟล์อื่นๆ ตามตำแหน่งของไฟล์ที่กำลังดำเนินการอยู่
  • ย้ายไดเร็กทอรีปัจจุบันไปยังไดเร็กทอรีของไฟล์ที่กำลังดำเนินการ
  • การประมวลผลเดียวกันสามารถทำได้โดยไม่คำนึงถึงไดเร็กทอรีปัจจุบันขณะรันไทม์

ดูบทความต่อไปนี้สำหรับข้อมูลเกี่ยวกับการรับและเปลี่ยนไดเร็กทอรีปัจจุบัน (ไดเร็กทอรีการทำงาน)

โปรดทราบว่า __file__ ไม่สามารถใช้ได้ใน Jupyter Notebook (.ipynb)
ไดเร็กทอรีที่ .ipynb ตั้งอยู่จะถูกดำเนินการเป็นไดเร็กทอรีปัจจุบัน โดยไม่คำนึงถึงไดเร็กทอรีที่ Jupyter Notebook เริ่มทำงาน
เป็นไปได้ที่จะใช้ os.chdir() ในโค้ดเพื่อเปลี่ยนไดเร็กทอรีปัจจุบัน

os.getcwd() และ __file__

ใน Windows คุณสามารถใช้คำสั่ง dir แทน pwd เพื่อตรวจสอบไดเร็กทอรีปัจจุบัน

pwd
# /Users/mbp/Documents/my-project/python-snippets/notebook

สร้างไฟล์สคริปต์ Python (file_path.py) โดยมีเนื้อหาต่อไปนี้ในระดับล่าง (data\src)

import os

print('getcwd:      ', os.getcwd())
print('__file__:    ', __file__)

รันคำสั่ง python (หรือคำสั่ง python3 ในบางสภาพแวดล้อม) โดยระบุพาธไปยังไฟล์สคริปต์

python3 data/src/file_path.py
# getcwd:       /Users/mbp/Documents/my-project/python-snippets/notebook
# __file__:     data/src/file_path.py

พาธสัมบูรณ์ไปยังไดเร็กทอรีปัจจุบันสามารถรับได้ด้วย os.getcwd() คุณยังสามารถใช้ __file__ เพื่อรับเส้นทางที่ระบุโดยคำสั่ง python3

จนถึง Python 3.8 __file__ จะมีเส้นทางที่ระบุในคำสั่ง python (หรือ python3) ในตัวอย่างข้างต้น เส้นทางสัมพัทธ์ถูกส่งกลับเนื่องจากเป็นเส้นทางสัมพัทธ์ แต่เส้นทางสัมบูรณ์จะถูกส่งกลับหากเป็นเส้นทางแบบสัมบูรณ์

pwd
# /Users/mbp/Documents/my-project/python-snippets/notebook

python3 /Users/mbp/Documents/my-project/python-snippets/notebook/data/src/file_path.py
# getcwd:       /Users/mbp/Documents/my-project/python-snippets/notebook
# __file__:     /Users/mbp/Documents/my-project/python-snippets/notebook/data/src/file_path.py

Python 3.9 และใหม่กว่าจะคืนค่าพาธสัมบูรณ์ไปยัง __file__ โดยไม่คำนึงถึงพาธที่ระบุในคำสั่ง python (หรือ python3)

ในตัวอย่างต่อไปนี้ เราจะเพิ่มโค้ดลงในไฟล์สคริปต์เดียวกัน (file_path.py) ใน Python 3.7 และเรียกใช้โดยสัมพันธ์กับไดเร็กทอรีด้านบน

ใน Python 3.7 ใช้เส้นทางที่แน่นอน ผลลัพธ์จะแสดงอยู่ที่ส่วนท้ายของส่วนนี้

รับชื่อไฟล์และชื่อไดเร็กทอรีของไฟล์ที่กำลังดำเนินการอยู่

ในการรับชื่อไฟล์และชื่อไดเร็กทอรีของไฟล์ที่กำลังรันอยู่ ให้ใช้ฟังก์ชันต่อไปนี้ในโมดูล os.path ของไลบรารีมาตรฐาน

  • os.path.basename()
  • os.path.dirname()
print('basename:    ', os.path.basename(__file__))
print('dirname:     ', os.path.dirname(__file__))

ผลการดำเนินการ

# basename:     file_path.py
# dirname:      data/src

รับเส้นทางที่แน่นอนของไฟล์ที่กำลังดำเนินการ

หากได้รับพาธสัมพัทธ์ด้วย __file__ จะสามารถแปลงเป็นพาธสัมบูรณ์ด้วย os.path.abspath() ไดเร็กทอรียังสามารถได้รับเป็นเส้นทางที่แน่นอน

print('abspath:     ', os.path.abspath(__file__))
print('abs dirname: ', os.path.dirname(os.path.abspath(__file__)))

ผลการดำเนินการ

# abspath:      /Users/mbp/Documents/my-project/python-snippets/notebook/data/src/file_path.py
# abs dirname:  /Users/mbp/Documents/my-project/python-snippets/notebook/data/src

หากมีการระบุเส้นทางที่แน่นอนใน os.path.abspath() เส้นทางนั้นจะถูกส่งคืนตามที่เป็นอยู่ ดังนั้น หาก __file__ เป็นพาธสัมบูรณ์ ต่อไปนี้จะไม่ทำให้เกิดข้อผิดพลาด

  • os.path.abspath(__file__)

อ่านไฟล์อื่นๆ ตามตำแหน่งของไฟล์ที่กำลังดำเนินการอยู่

หากคุณต้องการอ่านไฟล์อื่นๆ ตามตำแหน่ง (พาธ) ของไฟล์ที่กำลังดำเนินการ ให้เข้าร่วมสองไฟล์ต่อไปนี้โดยใช้ os.path.join()

  • ไดเร็กทอรีของไฟล์ที่กำลังดำเนินการ
  • พาธสัมพัทธ์ไปยังไฟล์ที่จะอ่านจากไฟล์ที่รันอยู่

หากคุณต้องการอ่านไฟล์ในไดเร็กทอรีเดียวกันกับไฟล์ที่คุณกำลังรันอยู่ เพียงแค่เชื่อมชื่อไฟล์เข้าด้วยกัน

print('[set target path 1]')
target_path_1 = os.path.join(os.path.dirname(__file__), 'target_1.txt')

print('target_path_1: ', target_path_1)

print('read target file:')
with open(target_path_1) as f:
    print(f.read())

ผลการดำเนินการ

# [set target path 1]
# target_path_1:  data/src/target_1.txt
# read target file:
# !! This is "target_1.txt" !!

ระดับบนจะแสดงด้วย “. \” คุณสามารถปล่อยให้มันเป็นอยู่ แต่คุณสามารถใช้ os.path.normpath() เพื่อทำให้เส้นทางปกติและลบ “. \” และอักขระอื่น ๆ ออก

print('[set target path 2]')
target_path_2 = os.path.join(os.path.dirname(__file__), '../dst/target_2.txt')

print('target_path_2: ', target_path_2)
print('normalize    : ', os.path.normpath(target_path_2))

print('read target file:')
with open(target_path_2) as f:
    print(f.read())

ผลการดำเนินการ

# [set target path 2]
# target_path_2:  data/src/../dst/target_2.txt
# normalize    :  data/dst/target_2.txt
# read target file:
# !! This is "target_2.txt" !!

ย้ายไดเร็กทอรีปัจจุบันไปยังไดเร็กทอรีของไฟล์ที่กำลังดำเนินการ

ใช้ os.chdir() เพื่อย้ายไดเร็กทอรีปัจจุบันไปยังไดเร็กทอรีของไฟล์ที่กำลังดำเนินการในสคริปต์

คุณจะเห็นว่ามันถูกย้ายโดย os.getcwd()

print('[change directory]')
os.chdir(os.path.dirname(os.path.abspath(__file__)))
print('getcwd:      ', os.getcwd())

ผลการดำเนินการ

# [change directory]
# getcwd:       /Users/mbp/Documents/my-project/python-snippets/notebook/data/src

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

print('[set target path 1 (after chdir)]')
target_path_1 = 'target_1.txt'

print('target_path_1: ', target_path_1)

print('read target file:')
with open(target_path_1) as f:
    print(f.read())

print()
print('[set target path 2 (after chdir)]')
target_path_2 = '../dst/target_2.txt'

print('target_path_2: ', target_path_2)

print('read target file:')
with open(target_path_2) as f:
    print(f.read())

ผลการดำเนินการ

# [set target path 1 (after chdir)]
# target_path_1:  target_1.txt
# read target file:
# !! This is "target_1.txt" !!
# 
# [set target path 2 (after chdir)]
# target_path_2:  ../dst/target_2.txt
# read target file:
# !! This is "target_2.txt" !!

การประมวลผลเดียวกันสามารถทำได้โดยไม่คำนึงถึงไดเร็กทอรีปัจจุบันขณะรันไทม์

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

  • เชื่อมไดเร็กทอรีของไฟล์ที่รันอยู่และพาธสัมพัทธ์ไปยังไฟล์ที่จะอ่านจากไฟล์ที่รันอยู่โดยใช้ os.path.join()
  • ย้ายไดเร็กทอรีปัจจุบันไปยังไดเร็กทอรีของไฟล์ที่กำลังดำเนินการ

การย้ายไดเร็กทอรีปัจจุบันง่ายกว่า แต่แน่นอน หากคุณต้องการอ่านหรือเขียนไฟล์เพิ่มเติมหลังจากนั้น คุณต้องคำนึงว่าไดเร็กทอรีปัจจุบันถูกย้ายแล้ว

ผลลัพธ์ของตัวอย่างก่อนหน้านี้สรุปได้ด้านล่าง

pwd
# /Users/mbp/Documents/my-project/python-snippets/notebook

python3 data/src/file_path.py
# getcwd:       /Users/mbp/Documents/my-project/python-snippets/notebook
# __file__:     data/src/file_path.py
# basename:     file_path.py
# dirname:      data/src
# abspath:      /Users/mbp/Documents/my-project/python-snippets/notebook/data/src/file_path.py
# abs dirname:  /Users/mbp/Documents/my-project/python-snippets/notebook/data/src
# 
# [set target path 1]
# target_path_1:  data/src/target_1.txt
# read target file:
# !! This is "target_1.txt" !!
# 
# [set target path 2]
# target_path_2:  data/src/../dst/target_2.txt
# normalize    :  data/dst/target_2.txt
# read target file:
# !! This is "target_2.txt" !!
# 
# [change directory]
# getcwd:       /Users/mbp/Documents/my-project/python-snippets/notebook/data/src
# 
# [set target path 1 (after chdir)]
# target_path_1:  target_1.txt
# read target file:
# !! This is "target_1.txt" !!
# 
# [set target path 2 (after chdir)]
# target_path_2:  ../dst/target_2.txt
# read target file:
# !! This is "target_2.txt" !!

ผลลัพธ์ของการระบุเส้นทางที่แน่นอนมีดังนี้

pwd
# /Users/mbp/Documents/my-project/python-snippets/notebook

python3 /Users/mbp/Documents/my-project/python-snippets/notebook/data/src/file_path.py
# getcwd:       /Users/mbp/Documents/my-project/python-snippets/notebook
# __file__:     /Users/mbp/Documents/my-project/python-snippets/notebook/data/src/file_path.py
# basename:     file_path.py
# dirname:      /Users/mbp/Documents/my-project/python-snippets/notebook/data/src
# abspath:      /Users/mbp/Documents/my-project/python-snippets/notebook/data/src/file_path.py
# abs dirname:  /Users/mbp/Documents/my-project/python-snippets/notebook/data/src
# 
# [set target path 1]
# target_path_1:  /Users/mbp/Documents/my-project/python-snippets/notebook/data/src/target_1.txt
# read target file:
# !! This is "target_1.txt" !!
# 
# [set target path 2]
# target_path_2:  /Users/mbp/Documents/my-project/python-snippets/notebook/data/src/../dst/target_2.txt
# normalize    :  /Users/mbp/Documents/my-project/python-snippets/notebook/data/dst/target_2.txt
# read target file:
# !! This is "target_2.txt" !!
# 
# [change directory]
# getcwd:       /Users/mbp/Documents/my-project/python-snippets/notebook/data/src
# 
# [set target path 1 (after chdir)]
# target_path_1:  target_1.txt
# read target file:
# !! This is "target_1.txt" !!
# 
# [set target path 2 (after chdir)]
# target_path_2:  ../dst/target_2.txt
# read target file:
# !! This is "target_2.txt" !!

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

cd data/src

pwd
# /Users/mbp/Documents/my-project/python-snippets/notebook/data/src

python3 file_path.py
# getcwd:       /Users/mbp/Documents/my-project/python-snippets/notebook/data/src
# __file__:     file_path.py
# basename:     file_path.py
# dirname:      
# abspath:      /Users/mbp/Documents/my-project/python-snippets/notebook/data/src/file_path.py
# abs dirname:  /Users/mbp/Documents/my-project/python-snippets/notebook/data/src
# 
# [set target path 1]
# target_path_1:  target_1.txt
# read target file:
# !! This is "target_1.txt" !!
# 
# [set target path 2]
# target_path_2:  ../dst/target_2.txt
# normalize    :  ../dst/target_2.txt
# read target file:
# !! This is "target_2.txt" !!
# 
# [change directory]
# getcwd:       /Users/mbp/Documents/my-project/python-snippets/notebook/data/src
# 
# [set target path 1 (after chdir)]
# target_path_1:  target_1.txt
# read target file:
# !! This is "target_1.txt" !!
# 
# [set target path 2 (after chdir)]
# target_path_2:  ../dst/target_2.txt
# read target file:
# !! This is "target_2.txt" !!