* Robert Kern:
On 2010-03-03 13:32 PM, Alf P. Steinbach wrote:
* Robert Kern:
On 2010-03-03 11:18 AM, Alf P. Steinbach wrote:
* Robert Kern:
On 2010-03-03 09:56 AM, Alf P. Steinbach wrote:
* Mike Kent:
What's the compelling use case for this vs. a simple try/finally?

if you thought about it you would mean a simple "try/else".
"finally" is
always executed. which is incorrect for cleanup

Eh? Failed execution doesn't require cleanup? The example you gave is
definitely equivalent to the try: finally: that Mike posted.

Sorry, that's incorrect: it's not.

With correct code (mine) cleanup for action A is only performed when
action A succeeds.

With incorrect code cleanup for action A is performed when A fails.

Oh?

$ cat cleanup.py

class Cleanup:
def __init__( self ):
self._actions = []

def call( self, action ):
assert( 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" )

def print_(x):
print x

with Cleanup() as at_cleanup:
at_cleanup.call(lambda: print_("Cleanup executed without an exception."))

with Cleanup() as at_cleanup:

*Here* is where you should

1) Perform the action for which cleanup is needed.

2) Let it fail by raising an exception.


at_cleanup.call(lambda: print_("Cleanup execute with an exception."))
raise RuntimeError()

With an exception raised here cleanup should of course be performed.

And just in case you didn't notice: the above is not a test of the
example I gave.


$ python cleanup.py
Cleanup executed without an exception.
Cleanup execute with an exception.
Traceback (most recent call last):
File "cleanup.py", line 28, in <module>
raise RuntimeError()
RuntimeError

The actions are always executed in your example,

Sorry, that's incorrect.

Looks like it to me.

I'm sorry, but you're

1) not testing my example which you're claiming that you're testing, and

Then I would appreciate your writing a complete, runnable example that demonstrates the feature you are claiming. Because it's apparently not "ensur[ing] some desired cleanup at the end of a scope, even when the scope is exited via an exception" that you talked about in your original post.

Your sketch of an example looks like mine:

  with Cleanup as at_cleanup:
      # blah blah
      chdir( somewhere )
      at_cleanup.call( lambda: chdir( original_dir ) )
      # blah blah

The cleanup function gets registered immediately after the first chdir() and before the second "blah blah". Even if an exception is raised in the second "blah blah", then the cleanup function will still run. This would be equivalent to a try: finally:

# blah blah #1
chdir( somewhere )
try:
    # blah blah #2
finally:
    chdir( original_dir )

Yes, this is equivalent code.

The try-finally that you earlier claimed was equivalent, was not.



and not a try: else:

# blah blah #1
chdir( somewhere )
try:
    # blah blah #2
else:
    chdir( original_dir )

This example is however meaningless except as misdirection. There are infinitely many constructs that include try-finally and try-else, that the with-Cleanup code is not equivalent to. It's dumb to show one such.

Exactly what are you trying to prove here?

Your earlier claims are still incorrect.


Now, I assumed that the behavior with respect to exceptions occurring in the first "blah blah" weren't what you were talking about because until the chdir(), there is nothing to clean up.

There is no way that the example you gave translates to a try: else: as you claimed in your response to Mike Kent.

Of course there is.

Note that Mike wrapped the action A within the 'try':


<code author="Mike" correct="False">
   original_dir = os.getcwd()
   try:
       os.chdir(somewhere)
       # Do other stuff
   finally:
       os.chdir(original_dir)
       # Do other cleanup
</code>


The 'finally' he used, shown above, yields incorrect behavior.

Namely cleanup always, while 'else', in that code, can yield correct behavior /provided/ that it's coded correctly:


<code author="Alf" correct="ProbablyTrue" disclaimer="off the cuff">
   original_dir = os.getcwd()
   try:
       os.chdir(somewhere)
   except Whatever:
       # whatever, e.g. logging
       raise
   else:
       try:
           # Do other stuff
       finally:
           os.chdir(original_dir)
           # Do other cleanup
</code>


2) not even showing anything about your earlier statements, which were
just incorrect.

You're instead showing that my code works as it should for the case that
you're testing, which is a bit unnecessary since I knew that, but thanks
anyway.

It's the case you seem to be talking about in your original post.

What's this "seems"? Are you unable to read that very short post?


You seem to have changed your mind about what you want to talk about. That's fine.

And what's this claim about me changing any topic?


We don't have to stick with the original topic

Why not stick with the original topic?


, but I do ask you to acknowledge that you originally were talking about a feature that "ensure[s] some desired cleanup at the end of a scope, even when the scope is exited via an exception."

Yes, that's what it does.

Which is I why I wrote that.

This should not be hard to grok.


Do you acknowledge this?

This seems like pure noise, to cover up that you were sputing a lot of incorrect statements earlier.


I'm not sure what that shows, except that you haven't grokked this yet.


From your post, the scope guard technique is used "to ensure some
desired cleanup at the end of a scope, even when the scope is exited
via an exception." This is precisely what the try: finally: syntax is
for.

You'd have to nest it. That's ugly. And more importantly, now two people
in this thread (namely you and Mike) have demonstrated that they do not
grok the try functionality and manage to write incorrect code, even
arguing that it's correct when informed that it's not, so it's a pretty
fragile construct, like goto.

Uh-huh.

Yeah. Consider that you're now for the third time failing to grasp the
concept of cleanup for a successful operation.

Oh, I do. But if I didn't want it to run on an exception, I'd just write the code without any try:s or with:s at all.

# blah blah #1
chdir( somewhere )
# blah blah #2
chdir( original_dir )

Yes, but what's that got to do with anything?


The with statement allows you to encapsulate repetitive boilerplate
into context managers, but a general purpose context manager like your
Cleanup class doesn't take advantage of this.

I'm sorry but that's pretty meaningless. It's like: "A house allows you
to encapsulate a lot of stinking garbage, but your house doesn't take
advantage of that, it's disgustingly clean". Hello.

No, I'm saying that your Cleanup class is about as ugly as the try:
finally:. It just shifts the ugliness around. There is a way to use
the with statement to make things look better and more readable in
certain situations, namely where there is some boilerplate that you
would otherwise repeat in many places using try: finally:. You can
encapsulate that repetitive code into a class or a @contextmanager
generator and just call the contextmanager. A generic context manager
where you register callables doesn't replace any boilerplate. You
still repeat all of the cleanup code everywhere. What's more, because
you have to shove everything into a callable, you have significantly
less flexibility than the try: finally:.

Sorry, but that's meaningless again. You're repeating that my house has
no garbage in it.

No, I'm repeatedly saying that I think your solution stinks. I think it's ugly. I think it's restrictive. I think it does not improve on the available solutions.

First you'd have to understand it, simple as it is.


And you complain that it would be work to add garbage
to it. Why do you want that garbage? I think it's nice without it!

And you are entitled to that opinion. I am giving you mine.

Well, I'm sorry, but while you are entitled to an opinion it's not an opinion that carries any weight: first you need to get your facts and claims straight.

So far only this latest posting of yours has been free of directly incorrect statements.

But you still have a lot of statements that just show total incomprehension, like your example of achieving no cleanup in the case of an exception.


Cheers & hth.,

- Alf
--
http://mail.python.org/mailman/listinfo/python-list

Reply via email to