On 2015-09-21 15:56, Carl Meyer wrote:
My jaw dropped a bit when I saw it asserted in this thread that functions returning "useful value or None" is an anti-pattern. I write functions like that all the time, and I consider it a useful and necessary Python idiom. I would hate to rewrite all that code to either deal with exceptions or add default-value-argument boilerplate to all of them; when "no result" is an expected and normal possibility from a function, letting the calling code deal with None however it chooses is much nicer than either of those options.
I agree that it's a fine thing. The thing is, it's an API choice. If your API is "return such-and-such or None", then anyone who calls your function knows they have to check for None and do the right thing. I think this is fine if None really does indicate something like "no result". (The re module uses None return values this way.) It seems to me that a lot of the "problem" that these null-coalescing proposals are trying to solve is dealing with APIs that return None when they really ought to be raising an exception or returning some kind of context-appropriate empty value. If you're doing result = someFunction() and then result.attr.upper() and it's failing because result.attr is None, to me that's often a sign that the API is fragile, and the result object that someFunction returns should have its attr set to an empty string, not None. In other words, if you really want "a null result that I can call all kinds of string methods on and treat it like a string", you should be returning an empty string. If you want "a null result I can subscript and get an integer", you should be returning some kind of defaultdict-like object that has a default zero value. Or whatever. There isn't really such a thing as "an object to which I want to be able to do absolutely anything and have it work", because there's no type-general notion of what "work" means. From a duck-typing perspective, if you expect users to try to do anything with a value you return, what they might reasonably want to do should be a clue as to what kind of value you should return. That still leaves the use-case where you're trying to interoperate with some external system that may have missing values, but I don't see that as super compelling. Getting an exception when you do some['big']['json']['object']['value'] and one of the intermediate ones isn't there is a feature; the bug is the JavaScripty mentality of just silently passing around "undefined". To my mind, Python APIs that wrap such external data sources should ideally take the opportunity to improve on them and make them more Pythonic, by providing sensible, context-relevant defaults instead of propagating a generic "null" value willy-nilly. -- Brendan Barnwell "Do not follow where the path may lead. Go, instead, where there is no path, and leave a trail." --author unknown