Hướng dẫn python __file__

Tôi đang xây dựng một tập lệnh trợ giúp đơn giản cho công việc sẽ sao chép một vài tệp mẫu trong cơ sở mã của chúng tôi vào thư mục hiện tại. Tuy nhiên, tôi không có đường dẫn tuyệt đối đến thư mục nơi các mẫu được lưu trữ. Tôi có một đường dẫn tương đối từ tập lệnh nhưng khi tôi gọi tập lệnh thì nó xử lý nó như một đường dẫn liên quan đến thư mục làm việc hiện tại. Có cách nào để xác định rằng url tương đối này là từ vị trí của tập lệnh thay thế không?

Trong tệp có tập lệnh, bạn muốn làm một cái gì đó như thế này:

import os
dirname = os.path.dirname(__file__)
filename = os.path.join(dirname, 'relative/path/to/file/you/want')

Điều này sẽ cung cấp cho bạn đường dẫn tuyệt đối đến tệp bạn đang tìm kiếm. Lưu ý rằng nếu bạn đang sử dụng setuptools, có lẽ bạn nên sử dụng API tài nguyên gói thay vào đó.

UPDATE: Tôi đang trả lời một nhận xét ở đây để tôi có thể dán một mẫu mã. :-)

Tôi có đúng không khi nghĩ rằng __file__ không phải lúc nào cũng có sẵn (ví dụ: khi bạn chạy tệp trực tiếp thay vì nhập tệp)?

Tôi giả sử bạn có nghĩa là tập lệnh __main__ khi bạn đề cập đến việc chạy tệp trực tiếp. Nếu vậy, điều đó dường như không xảy ra trên hệ thống của tôi (python 2.5.1 trên OS X 10.5.7):

#foo.py
import os
print os.getcwd()
print __file__

#in the interactive interpreter
>>> import foo
/Users/jason
foo.py

#and finally, at the Shell:
~ % python foo.py
/Users/jason
foo.py

Tuy nhiên, tôi biết rằng có một số quirks với __file__ trên phần mở rộng C. Ví dụ: tôi có thể làm điều này trên máy Mac của mình:

>>> import collections #note that collections is a C extension in Python 2.5
>>> collections.__file__
'/System/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/lib-
dynload/collections.so'

Tuy nhiên, điều này làm tăng một ngoại lệ trên máy Windows của tôi.

bạn cần os.path.realpath (mẫu bên dưới thêm thư mục mẹ vào đường dẫn của bạn)

import sys,os
sys.path.append(os.path.realpath('..'))

Như đã đề cập trong câu trả lời được chấp nhận

import os
dir = os.path.dirname(__file__)
filename = os.path.join(dir, '/relative/path/to/file/you/want')

Tôi chỉ muốn thêm rằng

chuỗi sau không thể bắt đầu bằng dấu gạch chéo ngược, vì không có chuỗi nào nên bao gồm dấu gạch chéo ngược

Nó phải là một cái gì đó như

import os
dir = os.path.dirname(__file__)
filename = os.path.join(dir, 'relative','path','to','file','you','want')

Câu trả lời được chấp nhận có thể gây hiểu nhầm trong một số trường hợp, vui lòng tham khảo this link để biết chi tiết

Hãy xem xét mã của tôi:

import os


def readFile(filename):
    filehandle = open(filename)
    print filehandle.read()
    filehandle.close()



fileDir = os.path.dirname(os.path.realpath('__file__'))
print fileDir

#For accessing the file in the same folder
filename = "same.txt"
readFile(filename)

#For accessing the file in a folder contained in the current folder
filename = os.path.join(fileDir, 'Folder1.1/same.txt')
readFile(filename)

#For accessing the file in the parent folder of the current folder
filename = os.path.join(fileDir, '../same.txt')
readFile(filename)

#For accessing the file inside a sibling folder.
filename = os.path.join(fileDir, '../Folder2/same.txt')
filename = os.path.abspath(os.path.realpath(filename))
print filename
readFile(filename)

Xem sys.path Khi được khởi tạo khi khởi động chương trình, mục đầu tiên của danh sách này, đường dẫn [0], là thư mục chứa tập lệnh được sử dụng để gọi trình thông dịch Python.

Sử dụng đường dẫn này làm thư mục gốc mà bạn áp dụng đường dẫn tương đối của bạn

>>> import sys
>>> import os.path
>>> sys.path[0]
'C:\\Python25\\Lib\\idlelib'
>>> os.path.relpath(sys.path[0], "path_to_libs") # if you have python 2.6
>>> os.path.join(sys.path[0], "path_to_libs")
'C:\\Python25\\Lib\\idlelib\\path_to_libs'

Bây giờ là năm 2018 và Python đã phát triển thành __future__ từ lâu. Vậy làm thế nào về việc sử dụng tuyệt vời pathlib đến với Python 3.4 để hoàn thành nhiệm vụ thay vì đấu tranh với os, os.path, glob, shutil, v.v.

Vì vậy, chúng tôi có 3 đường dẫn ở đây (có thể trùng lặp):

  • mod_path: đó là đường dẫn của tập lệnh trợ giúp đơn giản
  • src_path: chứa một vài tệp mẫu đang chờ để được sao chép.
  • cwd: thư mục hiện tại , đích đến của các tệp mẫu đó.

và vấn đề là: chúng tôi không có đường dẫn đầy đủ của src_path, chỉ biết đó là đường dẫn tương đối cho mod_path.

Bây giờ chúng ta hãy giải quyết điều này với điều tuyệt vời pathlib :

# Hope you don't be imprisoned by legacy Python code :)
from pathlib import Path

# `cwd`: current directory is straightforward
cwd = Path.cwd()

# `mod_path`: According to the accepted answer and combine with future power
# if we are in the `helper_script.py`
mod_path = Path(__file__).parent
# OR if we are `import helper_script`
mod_path = Path(helper_script.__file__).parent

# `src_path`: with the future power, it's just so straightforward
relative_path_1 = 'same/parent/with/helper/script/'
relative_path_2 = '../../or/any/level/up/'
src_path_1 = (mod_path / relative_path_1).resolve()
src_path_2 = (mod_path / relative_path_2).resolve()

Trong tương lai, nó chỉ đơn giản như vậy. : D


Hơn nữa, chúng tôi có thể chọn và kiểm tra và sao chép/di chuyển các tệp mẫu đó bằng pathlib :

if src_path != cwd:
    # When we have different types of files in the `src_path`
    for template_path in src_path.glob('*.ini'):
        fname = template_path.name
        target = cwd / fname
        if not target.exists():
            # This is the COPY action
            with target.open(mode='wb') as fd:
                fd.write(template_path.read_bytes())
            # If we want MOVE action, we could use:
            # template_path.replace(target)

Thay vì sử dụng

import os
dirname = os.path.dirname(__file__)
filename = os.path.join(dirname, 'relative/path/to/file/you/want')

như trong câu trả lời được chấp nhận, nó sẽ mạnh mẽ hơn để sử dụng:

import inspect
import os
dirname = os.path.dirname(os.path.abspath(inspect.stack()[0][1]))
filename = os.path.join(dirname, 'relative/path/to/file/you/want')

bởi vì sử dụng __file__ sẽ trả về tệp mà mô-đun đã được tải, nếu nó được tải từ một tệp, vì vậy nếu tệp có tập lệnh được gọi từ nơi khác, thư mục được trả về sẽ không chính xác.

Những câu trả lời này cung cấp thêm chi tiết: https://stackoverflow.com/a/31867043/554225 và https://stackoverflow.com/a/50502/554225

Mã này sẽ trả về đường dẫn tuyệt đối đến tập lệnh chính.

import os
def whereAmI():
    return os.path.dirname(os.path.realpath(__import__("__main__").__file__))

Điều này sẽ làm việc ngay cả trong một mô-đun.

Xin chào, trước tiên bạn nên hiểu các hàm os.path.abspath (path)os.path.relpath (path)

Tóm lại os.path.abspath (đường dẫn) tạo một đường dẫn tương đối đến đường dẫn tuyệt đối. Và nếu đường dẫn được cung cấp chính nó là một đường dẫn tuyệt đối thì hàm trả về cùng một đường dẫn.

tương tự os.path.relpath (đường dẫn) tạo một đường dẫn tuyệt đối đến đường dẫn tương đối. Và nếu đường dẫn được cung cấp chính nó là một đường dẫn tương đối thì hàm trả về cùng một đường dẫn.

Ví dụ dưới đây có thể cho phép bạn hiểu đúng khái niệm trên:

giả sử tôi có một tệp input_file_list.txt chứa danh sách các tệp đầu vào được xử lý bởi tập lệnh python của tôi.

D:\conc\input1.dic

D:\conc\input2.dic

D:\Copyioconc\input_file_list.txt

Nếu bạn thấy cấu trúc thư mục ở trên, input_file_list.txt có trong thư mục Copyofconc và các tệp được xử lý bởi tập lệnh python có trong conc thư mục

Nhưng nội dung của tệp input_file_list.txt như dưới đây:

..\conc\input1.dic

..\conc\input2.dic

Và tập lệnh python của tôi có mặt trong D : ổ đĩa.

Và đường dẫn tương đối được cung cấp trong tệp input_file_list.txt có liên quan đến đường dẫn của input_file_list.txt tệp.

Vì vậy, khi kịch bản python sẽ thực thi thư mục làm việc hiện tại (sử dụng os.getcwd () để lấy đường dẫn)

Vì đường dẫn tương đối của tôi có liên quan đến input_file_list.txt, đó là "D:\Copyofconc", tôi phải thay đổi thư mục làm việc hiện tại thành "D:\Copyofconc ".

Vì vậy, tôi phải sử dụng os.chdir ('D:\Copyofconc'), vì vậy thư mục làm việc hiện tại sẽ là "D:\Copyofconc".

Bây giờ để lấy các tệp input1.dicinput2.dic, tôi sẽ đọc các dòng "..\conc\input1.dic" sau đó sẽ sử dụng lệnh

input1_path = os.path.abspath ('..\conc\input1.dic') (để thay đổi đường dẫn tương đối thành đường dẫn tuyệt đối. Ở đây, thư mục làm việc hiện tại là "D:\Copyofconc", tệp ".\conc\input1.dic" sẽ được truy cập liên quan đến "D:\Copyofconc")

vì vậy input1_path sẽ là "D:\conc\input1.dic"

Một thay thế phù hợp với tôi:

this_dir = os.path.dirname(__file__) 
filename = os.path.realpath("{0}/relative/file.path".format(this_dir))

Những gì làm việc cho tôi là sử dụng sys.path.insert. Sau đó, tôi chỉ định thư mục tôi cần phải đi. Ví dụ tôi chỉ cần lên một thư mục.

import sys
sys.path.insert(0, '../')