How do I correctly clean up a Python object?

后端 未结 10 1029
北荒
北荒 2020-11-22 16:59
class Package:
    def __init__(self):
        self.files = []

    # ...

    def __del__(self):
        for file in self.files:
            os.unlink(file)
         


        
相关标签:
10条回答
  • 2020-11-22 17:14

    I don't think that it's possible for instance members to be removed before __del__ is called. My guess would be that the reason for your particular AttributeError is somewhere else (maybe you mistakenly remove self.file elsewhere).

    However, as the others pointed out, you should avoid using __del__. The main reason for this is that instances with __del__ will not be garbage collected (they will only be freed when their refcount reaches 0). Therefore, if your instances are involved in circular references, they will live in memory for as long as the application run. (I may be mistaken about all this though, I'd have to read the gc docs again, but I'm rather sure it works like this).

    0 讨论(0)
  • 2020-11-22 17:20

    Here is a minimal working skeleton:

    class SkeletonFixture:
    
        def __init__(self):
            pass
    
        def __enter__(self):
            return self
    
        def __exit__(self, exc_type, exc_value, traceback):
            pass
    
        def method(self):
            pass
    
    
    with SkeletonFixture() as fixture:
        fixture.method()
    

    Important: return self


    If you're like me, and overlook the return self part (of Clint Miller's correct answer), you will be staring at this nonsense:

    Traceback (most recent call last):
      File "tests/simplestpossible.py", line 17, in <module>                                                                                                                                                          
        fixture.method()                                                                                                                                                                                              
    AttributeError: 'NoneType' object has no attribute 'method'
    

    Hope it helps the next person.

    0 讨论(0)
  • 2020-11-22 17:23

    The standard way is to use atexit.register:

    # package.py
    import atexit
    import os
    
    class Package:
        def __init__(self):
            self.files = []
            atexit.register(self.cleanup)
    
        def cleanup(self):
            print("Running cleanup...")
            for file in self.files:
                print("Unlinking file: {}".format(file))
                # os.unlink(file)
    

    But you should keep in mind that this will persist all created instances of Package until Python is terminated.

    Demo using the code above saved as package.py:

    $ python
    >>> from package import *
    >>> p = Package()
    >>> q = Package()
    >>> q.files = ['a', 'b', 'c']
    >>> quit()
    Running cleanup...
    Unlinking file: a
    Unlinking file: b
    Unlinking file: c
    Running cleanup...
    
    0 讨论(0)
  • 2020-11-22 17:24

    A better alternative is to use weakref.finalize. See the examples at Finalizer Objects and Comparing finalizers with __del__() methods.

    0 讨论(0)
  • 2020-11-22 17:27

    I think the problem could be in __init__ if there is more code than shown?

    __del__ will be called even when __init__ has not been executed properly or threw an exception.

    Source

    0 讨论(0)
  • 2020-11-22 17:29

    It seems that the idiomatic way to do this is to provide a close() method (or similar), and call it explicitely.

    0 讨论(0)
提交回复
热议问题