On Tue, Mar 6, 2018 at 12:58 AM, Ooomzay <ooom...@gmail.com> wrote: > Then that is indeed a challenge. From CPython back in 2.6 days up to > Python36-32 what I see is:- > > a Opened > b Opened > Traceback (most recent call last): > ... > AttributeError: 'C' object has no attribute 'dostuff' > a Closed > b Closed > >> Maybe exceptions aren't as easy to handle as you think? > > Well there is a general issue with exceptions owing to the ease > with which one can create cycles that may catch out newbs. But > that is not the case here. > >> Or maybe you >> just haven't tried any of this (which is obvious from the bug in your >> code > > Or maybe I just made a typo when simplifying my test case and failed to > retest? > > Here is my fixed case, if someone else could try it in CPython and report > back that would be interesting:- > > class RAIIFileAccess(): > def __init__(self, fname): > print("%s Opened" % fname) > self.fname = fname > > def __del__(self): > print("%s Closed" % self.fname) > > class A(): > def __init__(self): > self.res = RAIIFileAccess("a") > > class B(): > def __init__(self): > self.res = RAIIFileAccess("b") > > class C(): > def __init__(self): > self.a = A() > self.b = B() > > def main(): > c = C() > c.dostuff() > > main()
Tried this in the interactive interpreter again. >>> main() a Opened b Opened Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 3, in main AttributeError: 'C' object has no attribute 'dostuff' >>> Same problem! If you can't handle this situation, there's something fundamentally wrong with your system. Here's how I'd do it with context managers. from contextlib import contextmanager @contextmanager def file_access(fname): try: print("%s Opened" % fname) yield finally: print("%s Closed" % fname) @contextmanager def c(): try: print("Starting c") with file_access("a") as a, file_access("b") as b: yield finally: print("Cleaning up c") def main(): with c(): dostuff() # NameError >>> main() Starting c a Opened b Opened b Closed a Closed Cleaning up c Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 3, in main NameError: name 'dostuff' is not defined >>> And if you want different semantics, you can lay out c() differently - maybe have the try/finally not contain within the 'with' but be contained within it, or whatever else you like. Exceptions move through the stack exactly the way you'd expect them to. Instead of having an object to represent each resource, you simply have a function with the code needed to allocate and deallocate it. They nest perfectly. ChrisA -- https://mail.python.org/mailman/listinfo/python-list