2011-12-20 30 views
9

Tôi đã có một lớp kết thúc tốt đẹp một số chức năng xử lý tệp tôi cần. Một lớp khác tạo ra một thể hiện của filehandler và sử dụng nó trong một khoảng thời gian không xác định. Cuối cùng, caller bị hủy, sẽ hủy tham chiếu duy nhất thành filehandler.Trình bao bọc lớp quanh tệp - cách thích hợp để đóng xử lý tệp khi không còn tham chiếu

Cách tốt nhất để giữ filehandler đóng tệp là gì?

Tôi hiện đang sử dụng __del__(self) nhưng sau khi nhìn thấy severaldifferentquestionsand articles, tôi theo ấn tượng này được coi là một điều xấu .

class fileHandler: 
    def __init__(self, dbf): 
     self.logger = logging.getLogger('fileHandler') 
     self.thefile = open(dbf, 'rb') 
    def __del__(self): 
     self.thefile.close() 

Đó là bit liên quan của trình xử lý. Toàn bộ điểm của lớp là trừu tượng hóa các chi tiết về cách làm việc với đối tượng tệp cơ bản, và cũng để tránh đọc toàn bộ tệp vào bộ nhớ một cách không cần thiết. Tuy nhiên, một phần của việc xử lý tệp cơ bản sẽ đóng nó khi đối tượng nằm ngoài phạm vi.

caller không được coi là biết hoặc quan tâm đến các chi tiết liên quan đến số filehandler. Đây là công việc của filehandler để giải phóng mọi tài nguyên cần thiết có liên quan khi nó nằm ngoài phạm vi. Đó là một trong những lý do nó được tóm tắt ngay từ đầu. Vì vậy, tôi dường như phải đối mặt với việc di chuyển mã filehandler vào đối tượng gọi điện thoại hoặc xử lý sự trừu tượng bị rò rỉ.

Suy nghĩ?

Trả lời

11

__del__ không phải là một điều xấu. Bạn chỉ cần cẩn thận hơn để không tạo chu trình tham chiếu trong các đối tượng đã định nghĩa __del__. Nếu bạn thấy mình cần phải tạo chu kỳ (cha mẹ đề cập đến đứa trẻ có liên quan đến cha mẹ) thì bạn sẽ muốn sử dụng mô-đun weakref.

Vì vậy, __del__ không sao, chỉ cần cảnh giác với các tham chiếu về mạng.

Thu gom rác: Vấn đề quan trọng ở đây là khi một đối tượng đi ra khỏi phạm vi, nó thể được thu gom rác thải, và trong thực tế, nó sẽ được thu gom rác thải ... nhưng khi nào? Không có sự đảm bảo về thời gian và các triển khai Python khác nhau có các đặc điểm khác nhau trong lĩnh vực này. Vì vậy, để quản lý tài nguyên, bạn nên hiểu rõ hơn và thêm .close() vào số filehandler hoặc nếu việc sử dụng của bạn tương thích, hãy thêm các phương thức __enter____exit__.

__enter__ and __exit__ methods được mô tả tại đây. Một điều thực sự tốt đẹp về họ là __exit__ được gọi ngay cả khi ngoại lệ xảy ra, vì vậy bạn có thể đếm hoặc tài nguyên của bạn bị đóng một cách duyên dáng.

Mã của bạn, tăng cường cho __enter__/__exit__:

class fileHandler: 
    def __init__(self, dbf): 
     self.logger = logging.getLogger('fileHandler') 
     self.thefilename = dbf 
    def __enter__(self): 
     self.thefile = open(self.thefilename, 'rb') 
     return self 
    def __exit__(self, *args): 
     self.thefile.close() 

Lưu ý rằng các tập tin đã được mở cửa vào năm __enter__ thay vì __init__ - điều này cho phép bạn tạo đối tượng filehandler một lần, và sau đó sử dụng nó bất cứ khi nào bạn cần phải trong một with mà không cần tạo lại nó:

fh = filehandler('some_dbf') 
with fh: 
    #file is now opened 
    #do some stuff 
#file is now closed 
#blah blah 
#need the file again, so 
with fh: 
    # file is open again, do some stuff with it 
#etc, etc 
+0

Bí quyết tốt khi mở tệp trong '__enter __()' - bạn cũng có thể thực hiện một số phép thuật trong đó để giữ lại vị trí tệp giữa mở/đóng. – kindall

+1

Rất đẹp, điều này gần hơn với những gì tôi muốn. Các chu kỳ ref là điều đầu tiên tôi kiểm tra, và tôi không có bất kỳ. Nhưng một số bài báo nói rằng toàn bộ chuỗi đối tượng sẽ không thể thu thập được nếu một đối tượng lá có phương thức del, bất kể chu kỳ ref. –

+0

@SpencerRathbun: Tất cả tài liệu tôi có thể tìm thấy các trạng thái không thể thu thập được ** chỉ khi ** có chu kỳ ref. –

6

Như bạn đã viết, lớp học không làm cho tệp đóng lại đáng tin cậy hơn. Nếu bạn đơn giản thả cá thể tập tin trên sàn thì tệp sẽ không đóng cho đến khi đối tượng bị hủy. Điều này có thể ngay lập tức hoặc có thể không được cho đến khi đối tượng là rác thu thập được, nhưng chỉ cần thả một đối tượng tập tin đồng bằng trên sàn nhà sẽ đóng nó một cách nhanh chóng. Nếu tham chiếu duy nhất đến thefile là từ bên trong đối tượng lớp của bạn thì khi filehandler là rác thu thập thefile cũng sẽ bị thu gom rác và do đó đóng cùng một lúc.

Các cách chính xác để sử dụng file là sử dụng with tuyên bố:

with open(dbf, 'rb') as thefile: 
    do_something_with(thefile) 

đó sẽ đảm bảo rằng thefile luôn đóng bất cứ khi nào with thoát khoản. Nếu bạn muốn quấn tập tin của bạn bên trong đối tượng khác, bạn có thể làm điều đó quá bằng cách định nghĩa __enter____exit__ phương pháp:

class FileHandler: 
    def __init__(self, dbf): 
     self.logger = logging.getLogger('fileHandler') 
     self.thefile = open(dbf, 'rb') 
    def __enter__(self): 
     return self 
    def __exit__(self): 
     self.thefile.close() 

và sau đó bạn có thể làm:

with FileHandler(dbf) as fh: 
    do_something_with(fh) 

và chắc chắn các tập tin được đóng lại ngay lập tức .

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