For example, I have a function, that generates procedural noise
def procedural_noise(width, height, seed):
...
All of the parameters of this function should be positive. I suppose, that me need to check it and throw exception if on of parameters is non-positive. Is it a good (pythonic way) approach?
Let us suppose, that I am right. Which is the best way to check parameters?
I can write the checkers for each of parameters:
def procedural_noise(width, height, seed):
if width <= 0:
raise ValueError("Width should be positive")
if height <= 0:
raise ValueError("Height should be positive")
if seed <= 0:
raise ValueError("Seed should be positive")
...
It should be clearly for programmer when he will get exception, what he should to correct, but it's not good-looking in my opinion.
The following code is easier, but it is too far from ideal:
def procedural_noise(width, height, seed):
if width <= 0 or height <= 0 or seed <= 0:
raise ValueError("All of the parameters should be positive")
...
The last question: which is the best way to write tests with unittest
framework, that checks types of parameters and their values?
I can write the following function in a test class:
def test_positive(self):
self.assertRaises(ValueError, main.procedural_noise, -10, -10, 187)
Is it a correct solution?
UPD: I upvoted all answers, because each of them have a useful information for me, but I can't select the best answers of them (I suppose that it is fair to select most voted question tomorrow)
Also this could be a nice use case for function annotations (in Python 3). Example:
import inspect
from functools import wraps
def positive(name, value):
if value < 0:
raise ValueError(name + " must be positive")
def check_params(f):
signature = inspect.signature(f)
@wraps(f)
def wrapper(*args, **kwargs):
bound_arguments = signature.bind(*args, **kwargs)
for name, value in bound_arguments.arguments.items():
annotation = signature.parameters[name].annotation
if annotation is inspect.Signature.empty:
continue
annotation(name, value)
return f(*args, **kwargs)
return wrapper
@check_params
def procedural_noise(width: positive, height: positive, seed: positive):
pass # ...
It's a little bit of inspect-fu in the check_params
decorator (inspired by github.com/ceronman/typeannotations), but provides pretty nice and flexible way to check function arguments - without any if
s, for
s or other noise-code in the type-checked functions.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With