On 27.08.2020 16:01, Alex Hall wrote:
On Thu, Aug 27, 2020 at 3:37 PM M.-A. Lemburg
wrote: If I'm not mistaken, all those listed cases fall under the second case I mentioned (branching on length).
If your API allows for optional list entries, then it's better to branch on length (e.g. as in the pytest case). If this happens only in exceptional cases, use try-except (most other cases you listed).
All but the first example, i.e. all the uses of try-except, were found by grepping for `except IndexError`. That was just the easiest method I found to find examples. The fact that try-except was used in those cases does not necessarily mean that the index is missing "only in exceptional cases". Perhaps because you like to emphasise intent when you're coding you assume that "exceptional" is the intent when you see the keyword "except". It's not how I interpret these examples. I think truly exceptional cases would have a change in behaviour like showing a warning. All that's happening here is getting a default value, and using try-except is the easiest available syntax. Often the use case is that the list may be empty or you're at the edge of the list and you need to go one beyond. That's normal and expected, not exceptional. If list.get existed then probably it would have been used in many of these examples. But of course it didn't exist and I don't have a way of searching for custom get functions so nearly all the examples use except which you take to mean exceptional.
Could be that authors thought try-except to be the easier to use syntax, even when the length check is less effort to write, faster and clearer in stating that the missing items are expected. If those quoted code snippets really all refer to non-exceptional cases, it would be better to guide people to the length branching approach. And you could be right that some authors may have opted for list.get(), but the point of implementing such changes goes somewhat beyond "it reduced number of keystrokes". If it results in people writing less obvious code, it's usually not a good idea. Take e.g. the dict.get() interface. We should have not given it a default argument of default=None, since it's not obvious that mydict.get(x) will return None in case x is not part of mydict. Instead, it would have been better to require the default argument, so that you have to write mydict.get(x, None) or even mydict.get(x, default=None). That ship has sailed, but it should be warning to think twice about adding such apparently useful things. I had thought mx.Tools.get() would be useful at the time and it was easy to implement, along with several other additions. Many of them did not get much use. Others ended up in similar form in itertools or operator. The most useful addition was irange(), which I used a lot. Others had very similar needs and eventually enumerate() was added to the builtins. BTW: I also think that the analogy between dict.get() and list.get() is bit off... Asking a dict d of potentially any number of items for existence of a particular item x is somewhat different than asking a list l of a certain length i for the item at position i+1. The programmer should know that there is no item at position i+1. However, it's not obvious before trying that item x doesn't have a mapping in d by just looking at the object properties of d. -- Marc-Andre Lemburg eGenix.com Professional Python Services directly from the Experts (#1, Aug 27 2020)
Python Projects, Coaching and Support ... https://www.egenix.com/ Python Product Development ... https://consulting.egenix.com/
::: We implement business ideas - efficiently in both time and costs ::: eGenix.com Software, Skills and Services GmbH Pastor-Loeh-Str.48 D-40764 Langenfeld, Germany. CEO Dipl.-Math. Marc-Andre Lemburg Registered at Amtsgericht Duesseldorf: HRB 46611 https://www.egenix.com/company/contact/ https://www.malemburg.com/