0

Is there a convention for raising errors if the proper combination of key-word arguments is not provided in a function call?

As an example:

def convert(miles=0, kilometers=0):
  if miles and not kilometers:
    return miles * 1.61
  elif kilometers and not miles:
    return kilometers / 1.61
  else:
    raise #exception

In this function, the one or the other parameter must receive an argument; if there are zero or two arguments, the function is invalid.

The built-in exceptions do not include an exception that is obvious for this situation. The option I have considered is TypeError (used in other bad function calls). Is this the standard way to handle this situation or should I use a different exception?

By the way, I saw this question, but this is not what I am looking for.

Community
  • 1
  • 1
bcdan
  • 1,438
  • 1
  • 12
  • 25
  • How is that other question different from yours? – BrenBarn Aug 05 '15 at 16:29
  • He is talking about values. I am talking about arguments being there or not, zero representing no argument. – bcdan Aug 05 '15 at 16:30
  • 1
    @bcdan You're looking for **values of the arguments** rather than the arguments themselves. If the issue is absence of a positional argument (if user forgets to specify) the function would automatically raise a `TypeError`. – Renae Lider Aug 05 '15 at 18:58
  • You can always derive your own exception class from `Exception` and `raise` an instance of it. – martineau Aug 05 '15 at 19:10
  • 1
    @bcdan: You are talking about values. Zero is a value. You can't distinguish between the user passing in zero explicitly and not passing in a value at all. – BrenBarn Aug 05 '15 at 19:24

1 Answers1

2

ValueError
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.

https://docs.python.org/2/library/exceptions.html#exceptions.ValueError

One more thing...

If a function only has keyword arguments, users might confuse it as something they can call without specifying anything. Here you have no way of knowing which conversion they have in mind. You must have at least 2 positional arguments to calculate the values, or you can make two separate functions with one argument each.

I would recommend this:

def miles2km(miles=1):
    return miles * 1.60934

def km2miles(km=1):
    return 1.0/miles2km(1.0/km) if km else 0

The reason why I prefer this is because only one function needs to be maintained, since the conversion factor is only present in one of them.

Renae Lider
  • 1,004
  • 7
  • 20