
On Tue, 8 Aug 2023 at 00:09, Celelibi <celelibi@gmail.com> wrote:
Actually, now that I think about it, I guess a 'try' block without an 'except' and just a 'finally' would probably be a good candidate for a context manager. (Which I'm a big fan of. ^^)
Yeah, context managers are often a good way of writing a try/finally. Certainly not *always*, but they can be very elegant.
Here's what I think could be a not so far fetched example: writing a structured file through a serializing class. Conceptually the code could look like this:
myfile = MySerializer("foo.bin") try: # Write data with myfile.write() else: # Write footer with myfile.write() finally: myfile.close()
You might want to keep it as a 'try' statement instead of a 'with' because in the future you might want to handle some the exceptions generated by MySerializer but not those generated by the OS. (Although I agree, you can have a 'try' in a 'with'.)
Not sure how the generalization would go here, but in order to make "try-else" useful, it has to be highly likely that the "else" block be capable of raising the same exception that would be caught in the hypothetical "except" (and, importantly, that you not want this). I'm having trouble imagining what sort of exception would be like this, since a partly-written file is almost certainly not going to parse a useful footer. Maybe it's like a PKZIP file where the footer is actually measured from the end of the file?? Not a common technique by any means, although given Zip's ubiquity, maybe it deserves more consideration. Still, that would probably want to be coded as two entirely separate blocks, since - as per your comment - the "write out the central directory" part would have to happen when there's a serialization (or in this case, perhaps compression) problem, but NOT when there's other types of problem, or Ctrl-C, or anything like that.
And in the real world, that code might look something like this. It write two blocks of data, each preceeded by the data length and followed by a checksum. And the footer is the checksum of the whole data.
assert len(data) <= 256 myfile = MySerializer("foo.bin") try: myfile.write(128) myfile.write(data[:128]) myfile.write(crc32(data[:128])) myfile.write(len(data) - 128) myfile.write(data[128:]) myfile.write(crc32(data[128:])) myfile.write(crc32(data)) finally: myfile.close()
I don't know about you, but I don't think it's obvious which 'write' should be put in an 'else' block when an 'except' gets added. Even if we added comments to identify the data blocks and footers, it's not obvious that the exceptions that could be raised by writing the footer shouldn't be captured by the future 'except'.
Yeah, if there's a problem in any of these blocks, I have no idea what should get written. If the line "myfile.write(data[128:])", fails... do you write out its CRC? Do you write out the global CRC? You've already successfully written the length here, so I'd say the file is irreparably broken at that point, and all you can do is report that serialization failed. This is why real-world examples are so important. Inventing examples invariably leads to this sort of thing. You've had a marvellous attempt at it, and...
This example is not perfect, but here it is.
... exactly. ChrisA