
On Fri, Oct 1, 2021 at 3:02 PM Steven D'Aprano <steve@pearwood.info> wrote:
We might take the point of view that StopIteration is reserved for use by iterators, and that the interpreter reserves the use to treat *any* use of StopIteration in any other context as undefined behaviour, and that we ought to be grateful that the interpreter merely converts it to a RuntimeError instead of making demons fly out of your nose.
http://catb.org/jargon/html/N/nasal-demons.html
So I don't think we should be too gung-ho about generalising from StopIteration (a specific exception used by the interpreter for flow control) to arbitrary exceptions which represent error conditions.
If you want to generalise StopIteration at all, the next closest would be AttributeError, which exists so that getattr and __getattr__ can return any object whatsoever, or can signal "there is no object to return". But there's no equivalent of generators for them, or if there is, it is generators themselves: def __getattr__(self, attr): for value in self.__getattr_gen__(attr): return attr raise AttributeError def __getattr_gen__(self, attr): if attr.startswith("spam"): yield "ham" + attr[4:] You could argue that, now, an AttrributeError inside the gen function should be turned into RuntimeError. But that just brings us right back to context managers or try/except: def __getattr_(self, attr): try: for value in self.__getattr_gen__(attr): return attr except AttributeError: raise RuntimeError("Exception leaked from implementation function") raise AttributeError("Attribute not found: " + str(attr)) So ultimately, the true specialness of StopIteration is actually generators, not flow control. (Also: If anyone implements "pip install nasal-demons", I would be very curious as to its hardware requirements.) ChrisA