osdir.com


[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

RFC: Proposal: Deterministic Object Destruction


On Monday, 5 March 2018 13:59:35 UTC, Ooomzay  wrote:
> On Monday, 5 March 2018 11:24:37 UTC, Chris Angelico  wrote:
> > On Mon, Mar 5, 2018 at 10:09 PM, Ooomzay wrote:
> > > Here is an example of a composite resource using RAII:-
> > >
> > > class RAIIFileAccess():
> > >     def __init__(self, fname):
> > >         print("%s Opened" % fname)
> > >     def __del__(self):
> > >         print("%s Closed" % 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()
> > >
> > > Under this PEP this is all that is needed to guarantee that the files "a"
> > > and "b" are closed on exit from main or after any exception has been handled.
> > 
> > Okay. And all your PEP needs is for reference count semantics, right?
> > Okay. I'm going to run this in CPython, with reference semantics. You
> > guarantee that those files will be closed after an exception is
> > handled? Right.
> > 
> > >>> def main():
> > ...     c = C()
> > ...     c.do_stuff()
> > ...
> > >>> 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 'do_stuff'
> > >>>
> >  
> > Uhh.... I'm not seeing any messages about the files getting closed.
> 
> 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()
> 
> > You keep insisting that this is an easy thing.  > We keep pointing out
> > that it isn't. Now you're proving that you haven't even attempted any
> > of this. 
> 
> Nonsense. But you have got a result I have never seen in many years 
> and I would like to get to the  bottom of it.

Ahah... I see now you are running it from a shell so the exception is staying in scope. We just need to include normal exception handling in the example to fix this:-


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():
    try:
        c = C()
        c.dostuff()
    except:
        print("Boom!")

main()