Là rõ ràng đóng tập tin quan trọng?


149

Trong Python, nếu bạn mở tệp mà không gọi close()hoặc đóng tệp nhưng không sử dụng try- finallyhoặc withcâu lệnh "", đây có phải là vấn đề không? Hay nó là một thực hành mã hóa dựa vào bộ sưu tập rác Python để đóng tất cả các tệp? Ví dụ: nếu một người làm điều này:

for line in open("filename"):
    # ... do stuff ...

... Đây có phải là một vấn đề vì tập tin không bao giờ có thể bị đóng và một ngoại lệ có thể xảy ra khiến nó không được đóng? Hoặc nó chắc chắn sẽ bị đóng khi kết thúc fortuyên bố vì tập tin vượt quá phạm vi?


13
Các tập tin không đi ra khỏi phạm vi ở cuối forkhối. Số tham chiếu của nó sẽ về 0, khiến nó tự động bị đóng, nhưng chỉ các hàm, lớp và mô-đun xác định phạm vi trong Python, chứ không phải các câu lệnh ghép khác.
agf

18
Đó không phải là vấn đề trừ khi đó là vấn đề. Ở cấp độ HĐH, mọi tệp được mở bởi tập lệnh sẽ bị đóng khi tập lệnh thoát, do đó bạn không cần lo lắng về việc đóng tệp trong tập lệnh công cụ bỏ đi. Tuy nhiên, các quy trình có giới hạn về số lượng tệp mở mà chúng có thể duy trì, do đó, các tập lệnh phức tạp hoặc tồn tại lâu có thể cần phải cẩn thận hơn. Trong mọi trường hợp, đó là một thói quen tốt để đóng các tệp của bạn.
Russell Borogove

3
@agf: Bạn đúng rằng tệp không nằm ngoài phạm vi, nhưng nó không liên quan đến sự phân biệt giữa forcác khối và chức năng / lớp / mô-đun. Nó đơn giản hơn thế nhiều: các đối tượng không có phạm vi, chỉ có tên mới làm được. Không có tên nào đề cập đến đối tượng này, vì vậy không có gì ở đây để ở trong phạm vi hoặc đi ra khỏi phạm vi.
tối đa

@max Nhận xét của tôi đang sửa chữa giả định của mình rằng có một phạm vi liên quan đến forvòng lặp và đề cập rằng tệp bị đóng vì một lý do hoàn toàn khác. Nó không đi vào phạm vi nào trong Python, vì nó không liên quan ở đây.
agf

@max có một tham chiếu ngầm định trong phạm vi vòng lặp đó ... đây là một đối số về ngữ nghĩa
Peter R

Câu trả lời:


126

Trong ví dụ của bạn, tập tin không được đảm bảo sẽ bị đóng trước khi trình thông dịch thoát ra. Trong các phiên bản hiện tại của CPython, tệp sẽ bị đóng ở cuối vòng lặp for vì CPython sử dụng tính tham chiếu làm cơ chế thu gom rác chính nhưng đó là một chi tiết triển khai, không phải là một tính năng của ngôn ngữ. Các triển khai khác của Python không được đảm bảo để hoạt động theo cách này. Ví dụ: IronPython, PyPy và Jython không sử dụng tính năng tham chiếu và do đó sẽ không đóng tệp ở cuối vòng lặp.

Việc dựa vào triển khai bộ sưu tập rác của CPython là một thực tế tồi vì nó làm cho mã của bạn ít di động hơn. Bạn có thể không bị rò rỉ tài nguyên nếu bạn sử dụng CPython, nhưng nếu bạn đã từng chuyển sang triển khai Python không sử dụng tính năng tham chiếu, bạn sẽ cần xem qua tất cả mã của mình và đảm bảo tất cả các tệp của bạn được đóng đúng cách.

Ví dụ của bạn sử dụng:

with open("filename") as f:
     for line in f:
        # ... do stuff ...

8
Có sử dụng with open() as ftự động đóng tệp sau khi nó được thực hiện?
Rohan

24
@Rohan vâng, đó là phép thuật nhỏ mà withcâu lệnh cung cấp, nhưng tất nhiên để phép thuật này hoạt động, đối tượng phải có các phương thức đặc biệt __enter____exit__, sau đó, đối tượng thực hiện closevà bất kỳ công cụ dọn dẹp nào khác cần phải thực hiện tại kết thúc withtuyên bố ...
Copperfield

1
FYI: Câu trả lời này chỉ giải thích "khi nào nó sẽ bị đóng" nhưng không giải thích "nếu nó vẫn mở". Để đọc phần sau, vui lòng đọc phần "Điều gì sẽ xảy ra nếu một tệp vẫn mở?" tham gia vào câu trả lời này ( askubfox.com/questions/701491/ Google )
RayLuo

Ngoài ra, việc không đóng tệp có thể dẫn đến các tệp bị cắt bớt vì nội dung tệp chưa được xóa.
Erwan Legrand

Vì vậy, nếu tôi không đóng tệp, liệu tôi có lấy lại được bộ nhớ của mình một khi chương trình ngừng chạy không? Hay tôi thực sự phải bỏ ra khỏi toàn bộ phiên dịch?
Pro Q

22

Một số Pythons sẽ tự động đóng các tệp khi chúng không còn được tham chiếu, trong khi một số khác thì không và tùy thuộc vào O / S để đóng tệp khi trình thông dịch Python thoát.

Ngay cả đối với các Pythons sẽ đóng các tệp cho bạn, thời gian không được đảm bảo: có thể là ngay lập tức hoặc có thể là giây / phút / giờ / ngày sau đó.

Vì vậy, trong khi bạn có thể không gặp vấn đề với Python bạn đang sử dụng, thì chắc chắn không nên để các tệp của bạn mở. Trên thực tế, trong cpython 3, bạn sẽ nhận được cảnh báo rằng hệ thống phải đóng tệp cho bạn nếu bạn không làm điều đó.

Đạo đức: Dọn dẹp sau khi chính mình. :)


9
Các tệp bị đóng khi chúng không còn được tham chiếu trong CPython, nhưng đó không phải là một tính năng ngôn ngữ. Nếu đó là bạn có thể khá hạnh phúc dựa vào nó.
Peter Graham

9

Mặc dù khá an toàn khi sử dụng cấu trúc như vậy trong trường hợp cụ thể này, có một số lưu ý để khái quát hóa thực tiễn đó:

  • chạy có khả năng chạy hết các mô tả tập tin, mặc dù không thể, hãy tưởng tượng việc săn một lỗi như thế
  • bạn có thể không xóa được tệp đã nói trên một số hệ thống, ví dụ win32
  • nếu bạn chạy bất cứ thứ gì ngoài CPython, bạn không biết khi nào tệp được đóng cho bạn
  • nếu bạn mở tệp ở chế độ ghi hoặc đọc, bạn không biết khi nào dữ liệu bị xóa

3

Các tập tin nhận được rác được thu thập, và do đó đóng cửa. GC xác định khi nào nó bị đóng, không phải bạn. Rõ ràng, đây không phải là một cách thực hành được khuyến nghị vì bạn có thể đạt giới hạn xử lý tệp mở nếu bạn không đóng tệp ngay khi bạn sử dụng xong. Điều gì sẽ xảy ra nếu trong forvòng lặp đó của bạn, bạn mở thêm các tệp và để chúng tồn tại?


Nhưng nếu bạn đã mở các tệp khác trong vòng lặp đó, thì vẫn sẽ có nhiều hơn một tệp được mở đồng thời cho dù bạn có rõ ràng đóng bất kỳ tệp nào trong số chúng hay không. Bạn có nói rằng tập tin không nhất thiết phải được thu gom rác ngay khi tập tin vượt quá phạm vi, do đó nó sẽ bị đóng sớm hơn nếu được thực hiện rõ ràng? Còn khi một ngoại lệ xảy ra (khi bạn sử dụng với / thử-cuối cùng so với không làm như vậy) thì sao?
user553702

1
Trong CPython, việc đếm tham chiếu sẽ khiến nó được thu thập sau forcâu lệnh - bạn sẽ không phải đợi lần chạy bộ sưu tập rác tiếp theo.
agf

3

Xin chào Điều rất quan trọng là đóng mô tả tệp của bạn trong tình huống khi bạn sẽ sử dụng nội dung của nó trong cùng một tập lệnh python. Tôi hôm nay tự nhận ra sau khi sửa lỗi quá lâu. Lý do là nội dung sẽ được chỉnh sửa / xóa / lưu chỉ sau khi bạn đóng mô tả tệp và các thay đổi bị ảnh hưởng đến tệp!

Vì vậy, giả sử bạn có tình huống bạn viết nội dung vào một tệp mới và sau đó không đóng fd, bạn đang sử dụng tệp đó (không phải fd) trong một lệnh shell khác đọc nội dung của nó. Trong tình huống này, bạn sẽ không nhận được nội dung cho lệnh shell như mong đợi và nếu bạn cố gắng gỡ lỗi, bạn không thể tìm thấy lỗi dễ dàng. bạn cũng có thể đọc thêm trong mục blog của tôi http://magnificentzps.blogspot.in/2014/04/importance-of-closes-file-descriptor.html


1

Trong quá trình I / O, dữ liệu được đệm: điều này có nghĩa là nó được giữ ở một vị trí tạm thời trước khi được ghi vào tệp.

Python không xóa bộ đệm, nghĩa là ghi dữ liệu vào tập tin cho đến khi chắc chắn bạn đã viết xong. Một cách để làm điều này là đóng tệp.

Nếu bạn ghi vào một tệp mà không đóng, dữ liệu sẽ không chuyển đến tệp đích.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.