2017-01-20 8 views
0

私はクラスを含むpythonスクリプトを持っています。del self vs self .__ del __() - そして、Pythonでクリーンアップする適切な方法は何ですか?

このクラスには、通常のクリーンアップのための__del__メソッドがあります。スクリプトの通常の実行中にクラスを削除すると、クリーンアップが必要になります。

私はシグナルハンドラも持っていますが、それは異常なクリーンアップを行います。スクリプトがシグナルを受信したときに何か他のものを実行していた場合は、特別なクリーンアップを行い、続いて通常のクリーンアップを実行する必要があります。

del selfself.__del__()の間に違いがあることに気付きました。

つまり、self.__del__()delメソッドを2回呼び出します。

これがなぜ起こるのか説明してください。

これは、問題を説明するためのモックアップスクリプトです:

import sys 
import signal 
from optparse import OptionParser 


class TestClass(object): 
    def __init__(self, 
       del_self): 
     self.del_self = del_self 

     print "__init__ with del_self = %s" % self.del_self 

    def __del__(self): 
     print "Now performing usual cleanup." 

    def signal_handler(self, arg_1, arg_2): 
     print "Received signal. Now performing unusual cleanup." 

     # Unusual cleanup 

     print "Did unusual cleanup" 

     if self.del_self: 
      print("Doing del self") 
      del self 
     else: 
      print("Doing self.__del__()") 
      self.__del__() 

     sys.exit(0) 


if __name__ == '__main__': 
    arguments = sys.argv[1:] 
    parse = OptionParser("Test.") 
    parse.add_option(
     "-d", 
     "--delself", 
     help="Set del self.", 
     type="int", 
     default=1 
    ) 

    (options, _) = parse.parse_args() 

    print "Options: %s" % options 

    tc = TestClass(del_self=options.delself) 

    signal.signal(signal.SIGQUIT, tc.signal_handler) 

    while True: 
     pass 

私はスクリプトを実行した場合:

python deltest.py --delself 1 

そして問題killall -3 python私が手:

Received signal. Now performing unusual cleanup. 
Did unusual cleanup 
Doing del self 
Now performing usual cleanup. 

として、もし私がpython deltest.py --delself 0にもう一度killシグナルを送ると、私は得る:

Received signal. Now performing unusual cleanup. 
Did unusual cleanup 
Doing self.__del__() 
Now performing usual cleanup. 
Now performing usual cleanup. 

この場合、__del__メソッドが2回実行されるのはなぜですか?

ありがとうございます!

答えて

7

del selfはほとんどありません。ローカル変数という名前のが削除され、その名前はselfです。しかし、これはインスタンスへの最後の参照ではありません(このメソッドが呼び出されても参照は残っていますが、少なくともオブジェクトは存在し続けます)。

__del__を手動で呼び出すと、そのメソッドを実行する以外は何も実行されません。何も削除されません。

作業は、オブジェクトへの最後の参照を削除していない。この場合には、mainメソッド内のdel tcは、私の知る限り、その最後の参照を削除しなければなりません。オブジェクトがガベージコレクションされた後、Python__del__と呼びます。

したがって、__del__は、通常の関数として手動で呼び出すときは1回、プログラムが終了するとオブジェクトがガベージコレクションされるときは2回発生します。

+0

@ random_person_123:はい、これは詳細です[ここ](https://docs.python.org/2/reference/datamodel.html#object.__del__) –

+0

したがって、正しく理解していることを確認してください__del__はガベージコレクションの開始時に呼び出されるため、シグナルハンドラで呼び出す必要はありません。インスタンスがガベージコレクションされたときに自動的に呼び出されるためです。これは正しいです? – mayk93

+0

@ random_person_123:はい、決してそれを自分で呼び出すことはありません。オブジェクトがガベージコレクションされると自動的に呼び出されます。 CPythonは通常、最後の参照がなくなったときにそれを行いますが、正式にはPythonはオブジェクトのガベージコレクションを保証しません。 – RemcoGerlich

関連する問題