views:

159

answers:

6

Suppose in python you have a routine that accepts three named parameters (as **args), but any two out of these three must be filled in. If only one is filled in, it's an error. If all three are, it's an error. What kind of error would you raise ? RuntimeError, a specifically created exception, or other ?

+3  A: 

I would make a specific one. You can catch it and deal with that specific exception since it is a special circumstance that you created :)

Arthur Thomas
+5  A: 

If (as you say in one of the comments) that this is a programmer error, then you can raise AssertionError:

def two(**kwargs):
    assert len(kwargs) == 2, "Please only provide two args"

BTW, if you only have three named arguments, **kwargs seems like an odd way to do it. More natural might be:

def two(a=None, b=None, c=None):
    pass
Ned Batchelder
A: 

I would use a ValueError, or a subclass thereof: "Raised when a built-in operation or function receives an argument that has the right type but an inappropriate value, and the situation is not described by a more precise exception such as IndexError."

Passing 3 or 1 values when exactly 2 are required would technically be an inappropriate value if you consider all of the arguments a single tuple... At least in my opinion! :)

AKX
+6  A: 

Why not just do what python does?

>>> abs(1, 2, 3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: abs() takes exactly one argument (3 given)
Dustin
A: 

I recommend a custom exception. Like so:

class NeedExactlyTwo(ValueError):
    pass

Then you can raise NeedExactlyTwo in your code.

Be sure to document this in the docstring for your function.

steveha
+8  A: 

Remember that you can subclass Python's built-in exception classes (and TypeError would surely be the right built-in exception class to raise here -- that's what Python raises if the number of arguments does not match the signature, in normal cases without *a or **k forms in the signature). I like having every package define its own class Error(Exception), and then specific exceptions as needed can multiply inherit as appropriate, e.g.:

class WrongNumberOfArguments(thispackage.Error, TypeError):

Then, I'd raise WrongNumberOfArguments when I detect such a problem situation.

This way, any caller who's aware of this package can catch thispackage.Error, if they need to deal with any error specific to the package, while other callers (presumably up higher in the call chain) call still catch the more generic TypeError to deal with any errors such as "wrong number of arguments used in a function call".

Alex Martelli
This is a beautiful example of using multiple inheritance nicely. Thanks.
Noufal Ibrahim