Call __exit__ for all members of the class

Does Pythonic have an automatic way for __exit__all class members?

class C:
    def __init__(self):
        self.a = open('foo')
        self.b = open('bar')

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_value, traceback):
        # Is it correct to just forward the parameters here?
        self.a.__exit__(self, exc_type, exc_value, traceback)
        self.b.__exit__(self, exc_type, exc_value, traceback)

Can I do this without manually calling __exit__on aand b? I even call __exit__right?

Suppose the resources that I have are not file, as in the example, and there is no method like closeor destroy. Is it possible, for example, to apply a method like this on top of __enter__and __exit__?

+4
source share
4 answers

So, as I mentioned in the comment:

I think the most useful here would be: contextlib.ExitStack

__init__. enter_context(cm), cm - context_manager

def __init__(self):
    self.exit_stack = contextlib.ExitStack()
    self.exit_stack.__enter__()
    self.exit_stack.enter_context(open('foo')) 
    ....

, __exit__ .

ExitStack, init enter_context.

+3

__enter__ __exit__ . , , __exit__ , __exit__ .

, . .

from contextlib import contextmanager

class A:
    def __init__(self, filename0, filename1, file0, file1):
        self.filename0 = filename0
        self.filename1 = filename1
        self.file0 = file0
        self.file1 = file1

    @classmethod
    @contextmanager
    def create(cls, filename0, filename1):
        with open(filename0) as file0, \
                open(filename1) as file1:
            yield cls(filename0, filename1, file0, file1)

with A.create('file0.txt', 'file1.txt') as a:
    a.do_something()

, .

+1

__enter__ __exit__ . with. , - :

with C() as c:
    # stuff
# other stuff

. open __enter__ close __exit__

:

class C:
    def __enter__(self):
        self.a = open('foo')
        self.b = open('bar')
        return self

    def __exit__(self, exc_type, exc_value, traceback):
        self.a.close()
        self.b.close()

    def readline_a(self):
      return self.a.readline()

    def readline_b(self):
      return self.b.readline()

with C() as c:
  print(c.readline_a())
  print(c.readline_b())

foo bar

0

, - :

class MemberManager:
    managed_member_names = ('a', 'b', 'c')
    def __init__(self, a, b, c):
        self.a, self.b, self.c = a, b, c
    def __enter__(self):
        # yield statement means this enter method returns a generator
        for i in (getattr(self,n) for n self.managed_member_names):
            with open(i, mode="w") as x:
                # yield prevents the context manager from exiting
                yield x
    def __exit__(self, exc_type, exc_value, traceback):
        # all items will be closed by __enter__ context manager; nothing needed here
        pass

mm = MemberManager(fname1, fname2, fname3)
with mm as open_members:
    # open_members is a generator/iterator
    for member in open_members:
        member.write("foo")

, :

with mm as open_members:
    open_member_list = list(open_members)
    open_member_list[0].write("foo") # ValueError: I/O operation on closed file.

open_members , .

0

Source: https://habr.com/ru/post/1696246/


All Articles