Why not accept lists or arbitrary iterables in str.endswith?
I'm parsing configs for domain filtering rules, and they come as a list. However, str.endswith requires a tuple. So I need to use str.endswith(tuple(list)). I don't know the reasoning for this, but why not just accept a list as well?
On Jun 19, 2019, at 15:28, Soni L. <fakedme+py@gmail.com> wrote:
I'm parsing configs for domain filtering rules, and they come as a list. However, str.endswith requires a tuple. So I need to use str.endswith(tuple(list)). I don't know the reasoning for this, but why not just accept a list as well?
Strings are iterables. So, if endswith could accept arbitrary iterables, then endswith('abc') would mean the same as endswith(['a', 'b', 'c']), which would be very confusing. Or there’d be some special exception so it wouldn’t mean that when the iterable is a string, which might be less newbie-confusing, but would be even more confusing when you try to learn the details. (What would the details be? Remember that there’s also bytes.endswith, and bytearray.endswith, and they surely don’t want to distinguish with isinstance(arg, str), and even isinstance(arg, type(self)) is probably a bad idea unless you don’t want a bytearray to be able to take a bytes argument.) A better solution would be *args, so you don’t need a single argument that’s either a string or multiple strings. That’s how newer functions do “one or more whatevers”. The only problem is that *args didn’t exist at the time endswith was created (nor did the concept of “arbitrary iterable”). All of the old functions that do this (and a few newer functions that had good reasons to exactly ape the API of one of the old functions) use the same tuple-is-special rule, so you probably wouldn’t want to change one without changing all of them. And, if it wasn’t worth changing them in 2.2 or even 3.0 (presumably because backward compatibility outweighed the benefits), it probably isn’t worth changing them today either, but maybe you could make a case otherwise.
Those are good points, so what about a new method for this rather than an additional behavior for the existing method? After all, "explicit is better than implicit". New method names could be something like "beginswith_any" and "endswith_any", "find_any", "index_any", "count_any", ….
On Oct 13, 2019, at 04:56, Steve Jorgensen <stevej@stevej.name> wrote:
Those are good points, so what about a new method for this rather than an additional behavior for the existing method? After all, "explicit is better than implicit".
New method names could be something like "beginswith_any" and "endswith_any", "find_any", "index_any", "count_any", ….
This solves the backward compatibility problem. And I don’t think it doubles the cognitive load; you just have to remember the single new `_any` suffix, as long as it’s consistent so you don’t need to remember a lot of exceptions. But it does double the help text, docs, etc. Which will make it harder to look things up, and require more maintenance work to make sure you copy-and-paste-and-edit the docstring for two methods every time you add or modify one, and so on. If this really needs to be fixed, what’s wrong with using *args? For backward compatibility, a single arg continues to be “str or tuple of str”, but for new uses going forward you just never pass a tuple and instead write `x.endswith('spam', 'eggs', 'cheese')` or `x.endswith(*suffixes)` instead of `x.endswith(('spam', 'eggs', 'cheese'))` or `x.endswith(tuple(suffixes))`? That makes it consistent with everything else in Python, instead of requiring you to learn that string methods are special and have `_any` variants (and you only have to learn that string methods are special and take tuples if you’re implementing a new string method). It seems like this provides all the same benefits plus an extra one with no added cost. But I’m not sure why it needs to be fixed. As I said last time, nobody apparently thought it needed to be fixed in 2.2 or 3.0, so… why was that the wrong decision?
That makes a lot of sense. I do think this seems like useful-enough functionality to wand to add, and I like the idea of using _args_ as the means of implementation.
On Oct 13, 2019, at 19:03, Steve Jorgensen <stevej@stevej.name> wrote:
That makes a lot of sense.
When you’re replying, it really helps to quote what you’re replying to. I have no idea which of the messages in this thread you think makes sense (except that it’s probably one of the ones replying to you). Ideally your mail client lets you quote properly. If not, at least you can top-post your reply above (part of) the message you’re replying to; they all can do that.
Andrew Barnert wrote:
On Oct 13, 2019, at 19:03, Steve Jorgensen stevej@stevej.name wrote:
That makes a lot of sense. When you’re replying, it really helps to quote what you’re replying to. I have no idea which of the messages in this thread you think makes sense (except that it’s probably one of the ones replying to you). Ideally your mail client lets you quote properly. If not, at least you can top-post your reply above (part of) the message you’re replying to; they all can do that.
Sorry. Yes. I'm used to things like Slack these days and haven't used old-style mailing lists in a ling time. It takes some time to recall the best practices.
participants (3)
-
Andrew Barnert
-
Soni L.
-
Steve Jorgensen