Question

Programmer A writes the following function:

def compute_value(threshold = sys.float_info.max):
   ...
   return value

which has the optional parameter threshold which in a natural way has the maximum float value as a default to represent "no threshold".

Programmer B has also a representation for a threshold, but uses None to represent the absence of threshold. Unfortunately the compute_value function does not raise any exception if threshold=None but gives the incorrect answer. Hence a bug when programmer B passes None as threshold.

I would say that the best solution is to change the function in

def compute_value(threshold = None):
    if threshold is None:
        threshold = sys.float_info.max
    ...
    return value

since this function is more general than before, as it handles the None value in a way which makes sense.

This poses the question: is it always best to use only None as default values?

It is not the first time that functions having default parameters different from None cause trouble to me. In other situations I was finding myself to remove None values from a kwargs dictionary...

Another related (maybe silly) question. Actually programmer B modified the function above as follows:

def compute_value(threshold = sys.float_info.max):
    if threshold is None:
        threshold = sys.float_info.max
    ...
    return value

which is perfectly correct but seems bad to me. Bad because sys.float_info.max is repeated twice... but: is this a violation of the DRY principle? Because, strictly speaking, also None is repeated twice in the first implementation and both None and sys.float_info.max are constants.

Was it helpful?

Solution

This really boils down to whether or not you (the API provider) think that None should be a valid argument to pass to the function. Personally, in this case, I think I would use sys.float_info.max and disallow the use of None. After all, why should None go about masquerading as a float? The canonical use of None as a default argument is when you need a mutable default argument, but that isn't the case here.

There is an argument to made for the reverse -- If you use None, then help will tell you that the threshold is None, which makes some sense from a "read the code as text" perspective. (after all, you mean that there is no threshold).1

Ultimately though, it's mostly just splitting hairs at this point. Pick a convention, document it and stick with it. Don't worry about it too much.


1This is made even worse if you have auto-generated documentation (e.g. sphinx) and sys.float_info.max doesn't return the same value on computer which generates the documentation compared to the computer which runs the code. This scenario is a pretty unlikely one -- Most computers these days agree on IEEE, but ...

OTHER TIPS

You can also workaround None default values using kwargs

def compute_value(**kwargs):
    threshold = kwargs.get('threshold', sys.float_info.max)
    ...
    return value
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top