2018年10月27日 星期六

[ Python 常見問題 ] How do I correctly clean up a Python object?

Source From Here 
Question 
Check sample code below: 
  1. class Package:  
  2.     def __init__(self):  
  3.         self.files = []  
  4.   
  5.     # ...  
  6.   
  7.     def __del__(self):  
  8.         for file in self.files:  
  9.             os.unlink(file)  
__del__(self) above fails with an AttributeError exception. I understand Python doesn't guarantee the existence of "global variables" (member data in this context?) when __del__() is invoked. If that is the case and this is the reason for the exception, how do I make sure the object destructs properly? 

How-To 
I'd recommend using Python's with statement for managing resources that need to be cleaned up. The problem with using an explicit close() statement is that you have to worry about people forgetting to call it at all or forgetting to place it in a finally block to prevent a resource leak when an exception occurs. To use the with statement, create a class with the following methods: 
  1. def __enter__(self)  
  2. def __exit__(self, exc_type, exc_value, traceback)  
In your example above, you'd use: 
  1. class Package:  
  2.     def __init__(self):  
  3.         self.files = []  
  4.   
  5.     def __enter__(self):  
  6.         return self  
  7.   
  8.     # ...  
  9.   
  10.     def __exit__(self, exc_type, exc_value, traceback):  
  11.         for file in self.files:  
  12.             os.unlink(file)  
Then, when someone wanted to use your class, they'd do the following: 
  1. with Package() as package_obj:  
  2.     # use package_obj  
The variable package_obj will be an instance of type Package (it's the value returned by the __enter__ method). Its __exit__ method will automatically be called, regardless of whether or not an exception occurs. 

Another approach is to use atexit.register. For example: 
  1. # package.py  
  2. import atexit  
  3. import os  
  4.   
  5. class Package:  
  6.     def __init__(self):  
  7.         self.files = []  
  8.         atexit.register(self.cleanup)  
  9.   
  10.     def cleanup(self):  
  11.         print("Running cleanup...")  
  12.         for file in self.files:  
  13.             print("Unlinking file: {}".format(file))  
  14.             # 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: 
  1. >>> from package import *  
  2. >>> p = Package()  
  3. >>> q = Package()  
  4. >>> q.files = ['a', 'b', 'c']  
  5. >>> quit()  
  6. Running cleanup...  
  7. Unlinking file: a  
  8. Unlinking file: b  
  9. Unlinking file: c  
  10. Running cleanup...  
Supplement 
* Python 建構、初始與消滅 
如果要定義物件被垃圾收集(Garbage collection)時,所要進行的資源清除動作,則可以定義__del__()方法,物件會被資源回收的資格,基本上就是參考至物件的變數計數為0的時候...


沒有留言:

張貼留言

[Git 常見問題] error: The following untracked working tree files would be overwritten by merge

  Source From  Here 方案1: // x -----删除忽略文件已经对 git 来说不识别的文件 // d -----删除未被添加到 git 的路径中的文件 // f -----强制运行 #   git clean -d -fx 方案2: 今天在服务器上  gi...