Câu trả lời:
Câu trả lời cho câu hỏi đó phụ thuộc phần nào vào việc triển khai Python cụ thể.
Để hiểu tất cả những điều này là gì, đặc biệt chú ý đến file
đối tượng thực tế . Trong mã của bạn, đối tượng đó chỉ được đề cập một lần, trong một biểu thức và không thể truy cập ngay sau khi read()
cuộc gọi trở lại.
Điều này có nghĩa là đối tượng tập tin là rác. Câu hỏi duy nhất còn lại là "Khi nào thì trình thu gom rác sẽ thu thập đối tượng tệp?".
trong CPython, sử dụng bộ đếm tham chiếu, loại rác này được chú ý ngay lập tức và vì vậy nó sẽ được thu gom ngay lập tức. Điều này thường không đúng với các triển khai trăn khác.
Một giải pháp tốt hơn, để đảm bảo rằng tệp được đóng, là mẫu này:
with open('Path/to/file', 'r') as content_file:
content = content_file.read()
sẽ luôn đóng tệp ngay sau khi khối kết thúc; ngay cả khi một ngoại lệ xảy ra.
Chỉnh sửa: Để đặt một điểm tốt hơn trên nó:
Khác với file.__exit__()
, được gọi là "tự động" trong with
cài đặt trình quản lý ngữ cảnh, cách duy nhất khác file.close()
được gọi tự động (nghĩa là, ngoài việc tự gọi nó một cách rõ ràng,) là thông qua file.__del__()
. Điều này dẫn chúng ta đến câu hỏi khi nào __del__()
được gọi?
Một chương trình được viết chính xác không thể cho rằng các trình hoàn thiện sẽ chạy tại bất kỳ thời điểm nào trước khi kết thúc chương trình.
- https://devbloss.microsoft.com/oldnewthing/20100809-00/?p=13203
Đặc biệt:
Đối tượng không bao giờ bị phá hủy rõ ràng; tuy nhiên, khi chúng không thể truy cập được, chúng có thể được thu gom rác. Việc triển khai được phép hoãn thu gom rác hoặc bỏ qua hoàn toàn - đó là vấn đề về chất lượng thực hiện cách thức thu gom rác được thực hiện, miễn là không có đối tượng nào được thu thập mà vẫn có thể truy cập được.
[...]
CPython hiện đang sử dụng sơ đồ đếm tham chiếu với phát hiện chậm (tùy chọn) rác được liên kết theo chu kỳ, thu thập hầu hết các đối tượng ngay khi chúng không thể truy cập được, nhưng không được bảo đảm để thu gom rác chứa các tham chiếu vòng tròn.
- https://docs.python.org/3.5/reference/datamodel.html#objects-values-and-types
(Nhấn mạnh của tôi)
nhưng như nó cho thấy, các triển khai khác có thể có hành vi khác. Ví dụ, PyPy có 6 triển khai thu gom rác khác nhau !
__exit__()
trong trường hợp như vậy nghe có vẻ như một lỗ hổng thiết kế.
try
/ finally
khó hiểu và vô dụng rất phổ biến đối với các trình xử lý dọn dẹp đã with
giải quyết. Sự khác biệt giữa "đóng rõ ràng" và "quản lý với with
" là trình xử lý thoát được gọi ngay cả khi ném ngoại lệ. Bạn có thể đặt close()
một finally
mệnh đề, nhưng điều đó không khác nhiều so với việc sử dụng with
thay vào đó, một chút lộn xộn hơn (3 dòng thêm thay vì 1) và khó hơn một chút để làm cho đúng.
with foo() as f: [...]
về cơ bản là giống như f = foo()
, f.__enter__()
[...] và f.__exit__()
với ngoại lệ xử lý , do đó __exit__
luôn gọi. Vì vậy, các tập tin luôn luôn được đóng lại.
Bạn có thể sử dụng pathlib .
Đối với Python 3.5 trở lên:
from pathlib import Path
contents = Path(file_path).read_text()
Đối với các phiên bản cũ hơn của Python, hãy sử dụng pathlib2 :
$ pip install pathlib2
Sau đó:
from pathlib2 import Path
contents = Path(file_path).read_text()
Đây là thực read_text
hiện thực tế :
def read_text(self, encoding=None, errors=None):
"""
Open the file in text mode, read it, and close the file.
"""
with self.open(mode='r', encoding=encoding, errors=errors) as f:
return f.read()
Chà, nếu bạn phải đọc từng dòng tệp để làm việc với từng dòng, bạn có thể sử dụng
with open('Path/to/file', 'r') as f:
s = f.readline()
while s:
# do whatever you want to
s = f.readline()
Hoặc thậm chí cách tốt hơn:
with open('Path/to/file') as f:
for line in f:
# do whatever you want to
Thay vì truy xuất nội dung tệp dưới dạng một chuỗi, có thể thuận tiện để lưu trữ nội dung dưới dạng danh sách tất cả các dòng mà tệp bao gồm :
with open('Path/to/file', 'r') as content_file:
content_list = content_file.read().strip().split("\n")
Có thể thấy, người ta cần thêm các phương thức nối .strip().split("\n")
vào câu trả lời chính trong chuỗi này .
Ở đây, .strip()
chỉ cần xóa các khoảng trắng và ký tự dòng mới ở phần cuối của toàn bộ chuỗi tệp và .split("\n")
tạo danh sách thực tế thông qua việc tách toàn bộ chuỗi tệp ở mỗi ký tự dòng mới \ n .
Hơn nữa, theo cách này, toàn bộ nội dung tệp có thể được lưu trữ trong một biến, có thể được mong muốn trong một số trường hợp, thay vì lặp qua từng dòng tệp như được chỉ ra trong câu trả lời trước này .