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