"Pythonic" way to differentiate between a string and a list of strings
This seems to be a relatively common issue in Python: you want to have a nice flexible API which can either accept a single argument, or multiple arguments in the form of a list. But, since strings are iterable (and iterating through them returns strings), the Pythonic Ask for Forgiveness Rather than Permission style doesn't seem to immediately work, since trying to iterate through your argument will work without error, whether you're being passed a collection or just a single string.
The best solution I know of is to just type check your arguments with a isinstance(foo, basestring) (as described in this stack overflow question). However, this feels very un-Pythonic in both its asking for permission rather than foregiveness, and in its dependency on type hierarchies rather than duck typing. Does anyone have a different (better) way of differentiating between an input list of strings, and just a regular string? Or is this solution just an unavoidable compromise?
Posted Mar 27, 2018, 6:10 PM UTC
you could only accept lists, even if it is no or even one argument. Makes everything easier.
I'd consider it generally poor practice for a function to accept a list but not a tuple. Of course, you could add tuples to your check, but that starts feeling very finnickey, and then do we also want to allow sets? Do we allow types which inherit from a list? At the very least, it doesn't strike me as a generally applicable rule of thumb.
They're talking about the API design, not the type checking or Python code. A function that expects either a single string or a list of - arbitrary? - other arguments is a red flag for a poorly designed function in the first place. So instead of having "a nice flexible API which can either accept a single argument, or multiple arguments in the form of a list", you instead have "an even nicer API which expects its arguments in exactly one standardized form".
Would it still behave weirdly if you pass it a string, which is an iterable? Maybe, but there are presumably limitless inputs that would cause the function to fail, and the only thing special about strings in this regard is that they are common. "Ask for Forgiveness Rather than Permission" goes both ways. If someone gives your function an input that will make it explode, you should have a concrete reason (such as actually being able to fix the problem) before you do anything besides let it.
I disagree. This is something I've come across several times when writing recursive functions with nested lists of strings.
When you are doing that (eg flattening arbitrarily nested lists, or whatever) your base case is already a type check by definition. So strings in the lists can interfere with the function, but the problem is solved by adding strings (and whatever else might come along, ie bytes) to the type check that's already there anyway. That might not seem elegant (though I wouldn't call it inelegant, either) but I doubt it's what motivated OP's question and I don't see how it's particularly relevant. What am I missing?