2011-08-19 29 views
85

Tôi không hiểu được __file__. Từ những gì tôi hiểu, __file__ trả về đường dẫn tuyệt đối mà từ đó mô-đun được tải.Python __file__ thuộc tính tuyệt đối hoặc tương đối?

Tôi đang gặp sự cố khi sản xuất: Tôi có một số abc.py với một tuyên bố print __file__, chạy từ /d/projects/python abc.py trả về abc.py. chạy từ /d/ trả lại projects/abc.py. Có lý do gì không?

+10

Đây là những gì Guido phải nói về điều này: http://mail.python.org/pipermail/python-dev/2010-February/097461.html – kindall

+0

Liên quan: https://stackoverflow.com/q/9271464/ 1959808 –

Trả lời

83

Từ documentation:

__file__ là tên đường dẫn của tập tin mà từ đó các mô-đun đã được nạp, nếu nó đã được nạp từ một tập tin. Thuộc tính __file__ không có mặt cho các mô-đun C được liên kết tĩnh vào trình thông dịch; cho các mô-đun mở rộng được nạp động từ một thư viện được chia sẻ, đó là tên đường dẫn của tệp thư viện được chia sẻ.

Từ mailing list thread liên kết bởi @kindall trong một chú thích cho câu hỏi:

tôi đã không cố gắng để repro ví dụ cụ thể này, nhưng lý do là mà chúng ta không muốn có để gọi getpwd() trên mọi lần nhập cũng không làm chúng tôi muốn có một số loại biến trong quá trình để lưu trữ thư mục hiện tại. (Getpwd() là tương đối chậm và đôi khi có thể thất bại hoàn toàn, và cố gắng để cache nó có nguy cơ nhất định là sai.)

Chúng tôi làm gì thay vào đó, là mã trong site.py mà đi qua các yếu tố của sys.path và biến chúng thành đường dẫn tuyệt đối. Tuy nhiên mã này chạy trước khi '' được chèn vào trước mặt sys.path, do đó giá trị ban đầu của sys.path là ''.

Đối với phần còn lại của điều này, hãy xem xét sys.path không bao gồm ''.

Vì vậy, nếu bạn đang ở bên ngoài một phần của sys.path có chứa các mô-đun, bạn sẽ nhận được một đường dẫn tuyệt đối . Nếu bạn ở trong một phần của sys.path có chứa mô-đun, bạn sẽ nhận được đường dẫn tương đối.

Nếu bạn tải mô-đun trong thư mục hiện tại và thư mục hiện tại không phải là trong sys.path, bạn sẽ nhận được đường dẫn tuyệt đối.

Nếu bạn tải mô-đun trong thư mục hiện tại và thư mục hiện tại trong sys.path, bạn sẽ nhận được đường dẫn tương đối.

+0

do đó có nghĩa là nếu có một đường dẫn từ '' đến mô-đun, đường dẫn tương đối sẽ được sử dụng, nếu không phải là đường dẫn tuyệt đối sẽ được sử dụng vì phần còn lại của sys.path là tuyệt đối .. – goh

+4

Nếu bạn tải mô-đun trong thư mục hiện tại và thư mục hiện tại __isn't__ trong 'sys.path', bạn sẽ nhận được đường dẫn tuyệt đối. Nếu bạn tải một mô-đun trong thư mục hiện tại và thư mục hiện tại __is__ trong 'sys.path', bạn sẽ nhận được một đường dẫn tương đối. – agf

+0

Hãy nhớ rằng, vì mục đích này, 'sys.path' không bao gồm' '' '. – agf

4

Với sự trợ giúp của thư Guido được cung cấp bởi @kindall, chúng tôi có thể hiểu quy trình nhập chuẩn khi tìm mô-đun trong mỗi thành viên sys.path và tệp là kết quả của tra cứu này (chi tiết hơn trong PyMOTW Modules and Imports.). Vì vậy, nếu mô-đun được đặt trong đường dẫn tuyệt đối trong sys.path kết quả là tuyệt đối, nhưng nếu nó nằm trong đường dẫn tương đối trong sys.path kết quả là tương đối.

Bây giờ tập tin site.py khởi động chăm sóc của việc cung cấp chỉ đường dẫn tuyệt đối trong sys.path, ngoại trừ ban đầu '', vì vậy nếu bạn không thay đổi nó bằng các phương tiện khác hơn là thiết lập PYTHONPATH (có đường cũng được thực hiện tuyệt đối, trước khi tiền tố sys.path), bạn sẽ luôn nhận được một đường dẫn tuyệt đối, nhưng khi mô-đun được truy cập thông qua thư mục hiện tại.

Bây giờ, nếu bạn lừa sys.path theo cách hài hước, bạn có thể nhận bất kỳ thứ gì.

Một ví dụ nếu bạn có một mô-đun mẫu foo.py trong /tmp/ với mã:

import sys 
print(sys.path) 
print (__file__) 

Nếu bạn đi trong/tmp bạn nhận được:

>>> import foo 
['', '/tmp', '/usr/lib/python3.3', ...] 
./foo.py 

Khi ở trong /home/user, nếu bạn thêm /tmp của bạn PYTHONPATH bạn nhận được:

>>> import foo 
['', '/tmp', '/usr/lib/python3.3', ...] 
/tmp/foo.py 

Ngay cả khi bạn thêm ../../tmp, nó sẽ được chuẩn hóa và kết quả là như nhau.

Nhưng nếu thay vì sử dụng PYTHONPATH bạn sử dụng trực tiếp một số đường dẫn vui nhộn bạn sẽ nhận được kết quả hài hước như nguyên nhân.

>>> import sys 
>>> sys.path.append('../../tmp') 
>>> import foo 
['', '/usr/lib/python3.3', .... , '../../tmp'] 
../../tmp/foo.py 

Guido giải thích trong các chủ đề nêu trên, tại sao python không nên cố gắng để chuyển đổi tất cả các mục trong đường dẫn tuyệt đối:

chúng tôi không muốn phải gọi getpwd() trên mỗi khẩu. ... getpwd() là tương đối chậm và đôi khi có thể thất bại hoàn toàn,

vì vậy, con đường của bạn được sử dụng vì nó là.

40

__file__ là tuyệt đối since Python 3.4, trừ khi thực hiện một kịch bản trực tiếp sử dụng một đường dẫn tương đối:

Mô-đun __file__ thuộc tính (và giá trị liên quan) nên bây giờ lúc nào cũng chứa đường dẫn tuyệt đối theo mặc định, với ngoại lệ duy nhất của __main__.__file__ khi một tập lệnh đã được thực hiện trực tiếp bằng cách sử dụng đường dẫn tương đối. (Đóng góp bởi Brett Cannon trong bpo-18416.)

Bạn không chắc chắn liệu nó có giải quyết được các liên kết tượng trưng hay không.

Ví dụ về đi qua một đường dẫn tương đối:

$ python script.py 
+0

Cảm ơn. Đây là một thực tế khó khăn để theo dõi! – meawoppl

+4

Điều này không đúng với Python 3.4.0 ('Python 3.4.0 (mặc định, ngày 11 tháng 4 năm 2014, 13:05:11) [GCC 4.8.2] trên linux'). Và các liên kết tượng trưng không được giải quyết trong các thử nghiệm của tôi. –

+0

@FrozenFlame, vui lòng báo cáo với https://bugs.python.org/ nếu 3.4.1 không khắc phục được. –

12

Cuối ví dụ đơn giản:

from os import path, getcwd, chdir 

def print_my_path(): 
    print('cwd:  {}'.format(getcwd())) 
    print('__file__:{}'.format(__file__)) 
    print('abspath: {}'.format(path.abspath(__file__))) 

print_my_path() 

chdir('..') 

print_my_path() 

Dưới Python-2.*, Cuộc gọi thứ hai sai xác định path.abspath(__file__) dựa trên thư mục hiện hành:

cwd:  C:\codes\py 
__file__:cwd_mayhem.py 
abspath: C:\codes\py\cwd_mayhem.py 
cwd:  C:\codes 
__file__:cwd_mayhem.py 
abspath: C:\codes\cwd_mayhem.py 

Theo ghi nhận của @techtonik, bằng Python 3.4 trở lên, điều này sẽ làm việc tốt kể từ __file__ trả về một đường dẫn tuyệt đối.

Các vấn đề liên quan