On Thu, 2 Mar 2017 at 03:07 Wolfgang Maier < wolfgang.ma...@biologie.uni-freiburg.de> wrote: [SNIP]
> As always though, reality can be expected to be quite a bit more > complicated than theory so I decided to check the stdlib for real uses > of break. This is quite a tedious task since break is used in many > different ways and I couldn't come up with a good automated way of > classifying them. So what I did is just go through stdlib code (in > reverse alphabetical order) containing the break keyword and put it into > categories manually. I only got up to socket.py before losing my > enthusiasm, but here's what I found: > > - overall I looked at 114 code blocks that contain one or more breaks > I wanted to say thanks for taking the time to go through the stdlib and doing such a thorough analysis of the impact of your suggestion! It always helps to have real-world numbers to know whether an idea will be useful (or not). > > - 84 of these are trivial use cases that simply break out of a while > True block or terminate a while/for loop prematurely (no use for any > follow-up clause there) > > - 8 more are causing a side-effect before a single break, and it would > be pointless to put this into an except break clause > > - 3 more cause different, non-redundant side-effects before different > breaks from the same loop and, obviously, an except break clause would > not help them either > > => So the vast majority of breaks does *not* need an except break *nor* > an else clause, but that's just as expected. > > > Of the remaining 19 non-trivial cases > > - 9 are variations of your classical search idiom above, i.e., there's > an else clause there and nothing more is needed > > - 6 are variations of your "nested side-effects" form presented above > with debatable (see above) benefit from except break > > - 2 do not use an else clause currently, but have multiple breaks that > do partly redundant things that could be combined in a single except > break clause > > - 1 is an example of breaking out of two loops; from sre_parse._parse_sub: > > [...] > # check if all items share a common prefix > while True: > prefix = None > for item in items: > if not item: > break > if prefix is None: > prefix = item[0] > elif item[0] != prefix: > break > else: > # all subitems start with a common "prefix". > # move it out of the branch > for item in items: > del item[0] > subpatternappend(prefix) > continue # check next one > break > [...] > > This could have been written as: > > [...] > # check if all items share a common prefix > while True: > prefix = None > for item in items: > if not item: > break > if prefix is None: > prefix = item[0] > elif item[0] != prefix: > break > except break: > break > > # all subitems start with a common "prefix". > # move it out of the branch > for item in items: > del item[0] > subpatternappend(prefix) > [...] > > > - finally, 1 is a complicated break dance to achieve sth that clearly > would have been easier with except break; from typing.py: > > [...] > def __subclasscheck__(self, cls): > if cls is Any: > return True > if isinstance(cls, GenericMeta): > # For a class C(Generic[T]) where T is co-variant, > # C[X] is a subclass of C[Y] iff X is a subclass of Y. > origin = self.__origin__ > if origin is not None and origin is cls.__origin__: > assert len(self.__args__) == len(origin.__parameters__) > assert len(cls.__args__) == len(origin.__parameters__) > for p_self, p_cls, p_origin in zip(self.__args__, > cls.__args__, > origin.__parameters__): > if isinstance(p_origin, TypeVar): > if p_origin.__covariant__: > # Covariant -- p_cls must be a subclass of > p_self. > if not issubclass(p_cls, p_self): > break > elif p_origin.__contravariant__: > # Contravariant. I think it's the > opposite. :-) > if not issubclass(p_self, p_cls): > break > else: > # Invariant -- p_cls and p_self must equal. > if p_self != p_cls: > break > else: > # If the origin's parameter is not a typevar, > # insist on invariance. > if p_self != p_cls: > break > else: > return True > # If we break out of the loop, the superclass gets a > chance. > if super().__subclasscheck__(cls): > return True > if self.__extra__ is None or isinstance(cls, GenericMeta): > return False > return issubclass(cls, self.__extra__) > [...] > > which could be rewritten as: > > [...] > def __subclasscheck__(self, cls): > if cls is Any: > return True > if isinstance(cls, GenericMeta): > # For a class C(Generic[T]) where T is co-variant, > # C[X] is a subclass of C[Y] iff X is a subclass of Y. > origin = self.__origin__ > if origin is not None and origin is cls.__origin__: > assert len(self.__args__) == len(origin.__parameters__) > assert len(cls.__args__) == len(origin.__parameters__) > for p_self, p_cls, p_origin in zip(self.__args__, > cls.__args__, > origin.__parameters__): > if isinstance(p_origin, TypeVar): > if p_origin.__covariant__: > # Covariant -- p_cls must be a subclass of > p_self. > if not issubclass(p_cls, p_self): > break > elif p_origin.__contravariant__: > # Contravariant. I think it's the > opposite. :-) > if not issubclass(p_self, p_cls): > break > else: > # Invariant -- p_cls and p_self must equal. > if p_self != p_cls: > break > else: > # If the origin's parameter is not a typevar, > # insist on invariance. > if p_self != p_cls: > break > except break: > # If we break out of the loop, the superclass gets > a chance. > if super().__subclasscheck__(cls): > return True > if self.__extra__ is None or isinstance(cls, > GenericMeta): > return False > return issubclass(cls, self.__extra__) > > return True > [...] > > > My summary: I do see use-cases for the except break clause, but, > admittedly, they are relatively rare and may be not worth the hassle of > introducing new syntax. > IOW out of 114 cases, 4 may benefit from an 'except' block? If I'm reading those numbers correctly then ~3.5% of cases would benefit which isn't high enough to add the syntax and related complexity IMO.
_______________________________________________ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/