RAII in Python - automatic destruction when leaving a scope

前端 未结 5 1140
我寻月下人不归
我寻月下人不归 2020-12-01 04:29

I\'ve been trying to find RAII in Python. Resource Allocation Is Initialization is a pattern in C++ whereby an object is initialized as it is created. If it fails, then it t

5条回答
  •  囚心锁ツ
    2020-12-01 04:52

    When switching to Python after years of C++, I have found it tempting to rely on __del__ to mimic RAII-type behavior, e.g. to close files or connections. However, there are situations (e.g. observer pattern as implemented by Rx) where the thing being observed maintains a reference to your object, keeping it alive! So, if you want to close the connection before it is terminated by the source, you won't get anywhere by trying to do that in __del__.

    The following situation arises in UI programming:

    class MyComponent(UiComponent):
    
        def add_view(self, model):
            view = TheView(model) # observes model
            self.children.append(view)
    
        def remove_view(self, index):
            del self.children[index] # model keeps the child alive
    

    So, here is way to get RAII-type behavior: create a container with add and remove hooks:

    import collections
    
    class ScopedList(collections.abc.MutableSequence):
    
        def __init__(self, iterable=list(), add_hook=lambda i: None, del_hook=lambda i: None):
            self._items = list()
            self._add_hook = add_hook
            self._del_hook = del_hook
            self += iterable
    
        def __del__(self):
            del self[:]
    
        def __getitem__(self, index):
            return self._items[index]
    
        def __setitem__(self, index, item):
            self._del_hook(self._items[index])
            self._add_hook(item)
            self._items[index] = item
    
        def __delitem__(self, index):
            if isinstance(index, slice):
                for item in self._items[index]:
                    self._del_hook(item)
            else:
                self._del_hook(self._items[index])
            del self._items[index]
    
        def __len__(self):
            return len(self._items)
    
        def __repr__(self):
            return "ScopedList({})".format(self._items)
    
        def insert(self, index, item):
            self._add_hook(item)
            self._items.insert(index, item)
    

    If UiComponent.children is a ScopedList, which calls acquire and dispose methods on the children, you get the same guarantee of deterministic resource acquisition and disposal as you are used to in C++.

提交回复
热议问题