Returning different types based on input parameters

George Sakkis george.sakkis at gmail.com
Mon Apr 6 17:02:26 EDT 2009


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 ?

George



More information about the Python-list mailing list