From: Robert Kern on 4 Mar 2010 20:04 On 2010-03-04 15:19 PM, Mike Kent wrote: > On Mar 3, 12:00 pm, Robert Kern<robert.k...(a)gmail.com> wrote: >> On 2010-03-03 09:39 AM, Mike Kent wrote: >> >>> What's the compelling use case for this vs. a simple try/finally? >> >>> original_dir = os.getcwd() >>> try: >>> os.chdir(somewhere) >>> # Do other stuff >>> finally: >>> os.chdir(original_dir) >>> # Do other cleanup >> >> A custom-written context manager looks nicer and can be more readable. >> >> from contextlib import contextmanager >> import os >> >> @contextmanager >> def pushd(path): >> original_dir = os.getcwd() >> os.chdir(path) >> try: >> yield >> finally: >> os.chdir(original_dir) >> >> with pushd(somewhere): >> ... > > Robert, I like the way you think. That's a perfect name for that > context manager! However, you can clear one thing up for me... isn't > the inner try/finally superfluous? My understanding was that there > was an implicit try/finally already done which will insure that > everything after the yield statement was always executed. No, the try: finally: is not implicit. See the source for contextlib.GeneratorContextManager. When __exit__() gets an exception from the with: block, it will push it into the generator using its .throw() method. This raises the exception inside the generator at the yield statement. -- Robert Kern "I have come to believe that the whole world is an enigma, a harmless enigma that is made terrible by our own mad attempt to interpret it as though it had an underlying truth." -- Umberto Eco
From: Alf P. Steinbach on 4 Mar 2010 20:59 * Steve Holden: > Alf P. Steinbach wrote: >> * Robert Kern: > [...] >>> No, it only argues that "with Cleanup():" is supernumerary. >> I don't know what "supernumerary" means, but to the degree that the >> argument says anything about a construct that is not 'finally', it says >> the same about general "with". >> > So rather than look up the meaning if a word you aren't familiar with > you will argue against its use in generic style? I haven't argued against the use of the word. I haven't done so in generic style, and I haven't argued against generic style use of the word, whatever it is you're trying to say. And I see that you're out trolling again, Steve Holden, implying all sorts of things that are untrue, as is evidently still your style. >> So whatever you mean by supernumerary, you're saying that the argument >> implies that "with" is supernumerary. >> >> This is starting to look like some earlier discussions in this group, >> where even basic logic is denied. >> > Why not just stick to the facts and forget about the earlier discussions? For yet another example, here you are implying that I'm not sticking to facts, which, again, is untrue, a technique that you should be ashamed of, Steve Holden. And since you're now injecting some Steve Holden'sk noise into this debate, chances are that in your points- and win/lose fixation you think I have scored a point immediately upthread, something which you think needs drowning in noise. Cheers, - Alf
From: Steve Howell on 4 Mar 2010 23:37 On Mar 3, 7:10 am, "Alf P. Steinbach" <al...(a)start.no> wrote: > For C++ Petru Marginean once invented the "scope guard" technique (elaborated on > by Andrei Alexandrescu, they published an article about it in DDJ) where all you > need to do to ensure some desired cleanup at the end of a scope, even when the > scope is exited via an exception, is to declare a ScopeGuard w/desired action. > > The C++ ScopeGuard was/is for those situations where you don't have proper > classes with automatic cleanup, which happily is seldom the case in good C++ > code, but languages like Java and Python don't support automatic cleanup and so > the use case for something like ScopeGuard is ever present. > > For use with a 'with' statement and possibly suitable 'lambda' arguments: > > <code> > class Cleanup: > def __init__( self ): > self._actions = [] > > def call( self, action ): > assert( is_callable( action ) ) > self._actions.append( action ) > > def __enter__( self ): > return self > > def __exit__( self, x_type, x_value, x_traceback ): > while( len( self._actions ) != 0 ): > try: > self._actions.pop()() > except BaseException as x: > raise AssertionError( "Cleanup: exception during cleanup" ) from > </code> > > I guess the typical usage would be what I used it for, a case where the cleanup > action (namely, changing back to an original directory) apparently didn't fit > the standard library's support for 'with', like > > with Cleanup as at_cleanup: > # blah blah > chdir( somewhere ) > at_cleanup.call( lambda: chdir( original_dir ) ) > # blah blah > > Another use case might be where one otherwise would get into very deep nesting > of 'with' statements with every nested 'with' at the end, like a degenerate tree > that for all purposes is a list. Then the above, or some variant, can help to > /flatten/ the structure. To get rid of that silly & annoying nesting. :-) > > Cheers, > > - Alf (just sharing, it's not seriously tested code) Hi Alf, I think I understand the notion you're going after here. You have multiple cleanup steps that you want to defer till the end, and there is some possibility that things will go wrong along the way, but you want to clean up as much as you can. And, of course, flatter is better. Is this sort of what you are striving for? class Cleanup: def __init__( self ): self._actions = [] def call( self, action ): self._actions.append( action ) def __enter__( self ): return self def __exit__( self, x_type, x_value, x_traceback ): while( len( self._actions ) != 0 ): try: self._actions.pop()() except BaseException as x: raise AssertionError( "Cleanup: exception during cleanup" ) def clean_the_floor(): print('clean the floor') def carouse(num_bottles, accident): with Cleanup() as at_cleanup: at_cleanup.call(clean_the_floor) for i in range(num_bottles): def take_down(i=i): print('take one down', i) at_cleanup.call(take_down) if i == accident: raise Exception('oops!') print ('put bottle on wall', i) carouse(10, None) carouse(5, 3)
From: Robert Kern on 4 Mar 2010 22:42 On 2010-03-04 16:27 , Alf P. Steinbach wrote: > * Mike Kent: >> However, I fail to understand his response that I must have meant try/ >> else instead, as this, as Mr. Kern pointed out, is invalid syntax. >> Perhaps Mr. Steinbach would like to give an example? > > OK. > > Assuming that you wanted the chdir to be within a try block (which it > was in your code), then to get code equivalent to my code, for the > purpose of a comparision of codes that do the same, you'd have to write > something like ... > > original_dir = os.getcwd() > try: > os.chdir(somewhere) > except Whatever: > # E.g. log it. > raise > else: > try: > # Do other stuff > finally: > os.chdir(original_dir) > # Do other cleanup > > ... which would be a more general case. > > I've also given this example in response to Robert earlier in the > thread. Although I haven't tried it I believe it's syntactically valid. > If not, then the relevant typo should just be fixed. :-) > > I have no idea which construct Robert thought was syntactically invalid. > I think that if he's written that, then it must have been something he > thought of. I was just trying to interpret what you meant by "Changing 'finally' to 'else' could make it equivalent." As far as I can tell, that has only one possible interpretation going by the plain meaning of the words, and it isn't yours. Since you always seem to refer to "try/else" as if it were an independent construct and not part of "try: except: else:" and no one else introduced except: clause, I must reiterate that your communications have been fabulously misleading. -- Robert Kern "I have come to believe that the whole world is an enigma, a harmless enigma that is made terrible by our own mad attempt to interpret it as though it had an underlying truth." -- Umberto Eco
From: Robert Kern on 4 Mar 2010 22:35
On 2010-03-04 15:12 , Mike Kent wrote: > On Mar 4, 12:30 pm, Robert Kern<robert.k...(a)gmail.com> wrote: > >> He's ignorant of the use cases of the with: statement, true. > > <humor> Ouch! Ignorant of the use cases of the with statement, am I? > Odd, I use it all the time.</humor> No, I was referring to Jean-Michel, who was not familiar with the with: statement. >> Given only your >> example of the with: statement, it is hard to fault him for thinking that try: >> finally: wouldn't suffice. > > <humor> Damn me with faint praise, will you?</humor> Also talking about Jean-Michel. :-) -- Robert Kern "I have come to believe that the whole world is an enigma, a harmless enigma that is made terrible by our own mad attempt to interpret it as though it had an underlying truth." -- Umberto Eco |