For example for the following method signature:
def genClusters(n_clusters, n_nodes, cluster_distribution):
n_clusters
should be an integer of more than 1.
n_nodes
should be an integer of more than n_clusters
cluster_distribution
should be a float between 0 and 1.
Should I use a series of if then raise exception
statements to handle the argument parameter bounds?
eg:
def genClusters(n_clusters, n_nodes, cluster_distribution):
if (cluster_distribution < 0 or cluster_distribution > 1):
raise ValueError("cluster distribution must be between 0 and 1")
if n_clusters < 1:
raise ValueError("n_clusters must be at least 1")
if n_nodes <= n_clusters:
raise ValueError("n_nodes must be at least n_clusters")
The second question is whether I should include these exception statements in every method that also calls this one.
For example:
def myFoo(foo, bar, bang):
clusters = genClusters(foo, bar, bang)
In this scenario, if foo, bar, or bang don’t fit previously defined parameter bounds, an exception will be thrown when genClusters
is called. So should I also be throwning exceptions at the start of myFoo
?
4
Say you don’t check the input arguments beforehand, and just let the function run its course. Consider this: what’s worst that’s going to happen? (This is not a rhetorical question.) Is giving it bad input going to:
- cause the function to fail with another exception somewhere deep in the code?
- waste a lot of time, then fail midway?
- do something potentially harmful (e.g. delete your valuable data …)?
- return a bogus result?
- cause a confusing error message?
Take these into consideration carefully. In most scenarios, where performance is not of utmost importance, you really want it to fail early and as loudly as possible, so checking for invalid arguments is generally a good idea (hopefully answers your first question).
This helps debugging and reduces the risk of your code doing something awful. Of course, this can be tedious at times, so if you want a quick approach (useful for prototyping), use assert
:
assert 0 <= cluster_distribution <= 1
However, there’s no use in doing it twice if it’s obvious that another function will do it for you, as it will lead to unnecessary code duplication (hopefully answers your second question).
For example, say you have a (rather useless) function like this:
def square_root(s);
return math.sqrt(s)
There’s no need to check whether s
is nonnegative because sqrt
does that already. In most “small” functions like this, you won’t need to do much input checking. Usually, only “big” functions require explicit input checking like these. In some cases, you can restructure code without explicit checks so that if the inputs are invalid it will fail automatically.