George Sakkis wrote:
That's more of a general API design question but I'd like to get an idea if and how things are different in Python context. AFAIK it's generally considered bad form (or worse) for functions/methods to return values of different "type" depending on the number, type and/or values of the passed parameters. I'm using "type" loosely in a duck- typing sense, not necessarily as a concrete class and its descendants, although I'm not sure if even duck-typing is endorsed for return values (as opposed to input parameters).For example, it is common for a function f(x) to expect x to be simply iterable, without caring of its exact type. Is it ok though for f to return a list for some types/values of x, a tuple for others and a generator for everything else (assuming it's documented), or it should always return the most general (iterator in this example) ? To take it further, what if f wants to return different types, differing even in a duck-type sense? That's easier to illustrate in a API-extension scenario. Say that there is an existing function `solve (x)` that returns `Result` instances. Later someone wants to extend f by allowing an extra optional parameter `foo`, making the signature `solve(x, foo=None)`. As long as the return value remains backward compatible, everything's fine. However, what if in the extended case, solve() has to return some *additional* information apart from `Result`, say the confidence that the result is correct ? In short, the extended API would be: def solve(x, foo=None): ''' @rtype: `Result` if foo is None; (`Result`, confidence) otherwise. ''' Strictly speaking, the extension is backwards compatible; previous code that used `solve(x)` will still get back `Result`s. The problem is that in new code you can't tell what `solve(x,y)` returns unless you know something about `y`. My question is, is this totally unacceptable and should better be replaced by a new function `solve2 (x, foo=None)` that always returns (`Result`, confidence) tuples, or it might be a justifiable cost ? Any other API extension approaches that are applicable to such situations ?
I don't like the sound of this. :-) In your example I would possibly suggest returning a 'Result' object and then later subclassing to give 'ConfidenceResult' which has the additional 'confidence' attribute. I think the only time when it's OK to return instances of different classes is when one of them is None, for example the re module where match() returns either a MatchObject (if successful) or None (if unsuccessful); apart from that, a function should always return an instance of the same class (or perhaps a subclass) or, if a collection then the same type of collection (eg always a list and never sometimes a list, sometimes a tuple). -- http://mail.python.org/mailman/listinfo/python-list
