2011-12-20 9 views
9

必要なファイル処理機能をラップするクラスがあります。別のクラスはfilehandlerのインスタンスを作成し、それを不定期に使用します。結局、callerが破壊され、filehandlerへの唯一の参照が破棄されます。ファイルのクラスラッパー - 参照されなくなったときにファイルハンドルを閉じる適切な方法

filehandlerにファイルを閉じる最も良い方法は何ですか?

私は現在__del__(self)を使用しますが、severaldifferentquestionsand articlesを見た後、私は、これは悪いことでは考えられている印象の下です。

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

これはハンドラの関連ビットです。クラスの全体のポイントは、基礎となるファイルオブジェクトの操作の詳細を抽象化し、ファイル全体を不必要にメモリに読み込まないようにすることです。しかし、オブジェクトがスコープから外れたときに、基礎となるファイルを処理することの一部がクローズされます。

callerは、filehandlerに記載されている内容を知っていたり、気にすることはありません。範囲外になったときに必要なリソースを解放するのはfilehandlerの仕事です。それが最初に抽象化された理由の1つです。だから、filehandlerコードを呼び出しオブジェクトに移動したり、漏れ抽象を扱うことに直面しているようです。

思考?

答えて

11

__del__は、それだけでは悪いものではありません。 __del__が定義されているオブジェクトでは、参照サイクルを作成しないように注意するだけです。サイクルを作成する必要がある場合(親は親を参照する子を参照します)、weakrefモジュールを使用することになります。

したがって、__del__は大丈夫です。ただ気をつけてください。

ガベージコレクション:ここで重要な点は、オブジェクトがスコープの外に出たとき、それはゴミが収集することができるということである、そして実際に、それゴミが収集されます...しかしとき?いつ、どこにPythonが実装されているかは保証されておらず、この分野では異なる特徴を持っています。したがって、リソースを管理する場合は、明示的にしてfilehandler.close()を追加するか、使用が互換性がある場合は__enter____exit__のメソッドを追加する方がよいでしょう。

ここでは、__enter__ and __exit__ methodsについて説明します。実際には、例外が発生しても__exit__が呼び出されているので、リソースを数えたり、リソースを正常に閉じることができます。

__enter__/__exit__のために強化あなたのコード、:ファイルが__enter__の代わり__init__で開かれていることを

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() 

注 - これは、あなたがかつてのFileHandlerオブジェクトを作成することを可能にし、いつでもあなた、それを使用しますそれを再作成しなくてもwithにする必要があります。

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

ニーストリック '__enterの__()'でファイルを開くと - あなたはまた、ファイルの位置を保持するために、そこにいくつかの魔法を行うことができます開閉間。 – kindall

+1

非常にいいです、これは私が望んでいたものに非常に近いです。 refサイクルは私がチェックした最初のもので、私は何も持っていません。しかし、いくつかの記事では、refサイクルにかかわらず、リーフオブジェクトにdelメソッドがある場合、オブジェクトチェーン全体が非回収可能であると言われています。 –

+0

@SpencerRathbun:私が見つけられたすべての文書は、アイテムが回収不能であることを示しています** ** refサイクルがある場合のみです。 –

6

あなたが書いたように、クラスによってファイルが確実に閉じることはありません。ファイルハンドラインスタンスを床に単純にドロップすると、オブジェクトが破棄されるまでファイルは閉じられません。これは、オブジェクトがガベージコレクトされるまで、すぐにでも、そうでなくてもかまいませんが、プレーンファイルオブジェクトをフロアにドロップするだけで、すぐに閉じられます。 thefileへの参照がクラスオブジェクト内からのものである場合、filehandlerがガベージコレクションされるときには、thefileもガベージコレクションされるため、同時に閉じられます。

ファイルを使用するための正しい方法はwith文で使用することです:

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

たびwith句が終了thefileが常に閉じていることを保証します。あなたが別のオブジェクト内のファイルをラップしたい場合は、あまりにも__enter____exit__方法定義することによって、それを行うことができます。

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() 

をして、あなたが行うことができます。

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

を、ファイルが速やかに閉じます確認してください。

関連する問題