12

Which standard python exception, if any, should be used in the case where a value is missing for the proper execution of a function ? TypeError and ValueError seemed good candidates to me but according to the documentation (my italics) :

Passing arguments of the wrong type (e.g. passing a list when an int is expected) should result in a TypeError, but passing arguments with the wrong value (e.g. a number outside expected boundaries) should result in a ValueError.

ValueError : Raised when an 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.

Neither of these descriptions seem to me to quite capture the idea of a missing value. But none of the other exceptions in the standard seem to come even close either.

Here's an example. Objects of type myclass can be instantiated in two different ways, each of which requires a specific parameter. If neither of them is provided, the init fails.

class myclass(object):
    def __init__(self,firstparam=None,secondparam=None):
        if firstparam:
             self.firstinit()
        elif secondparam:
             self.secondinit()
        else:
           #What to put here ?
           raise Exception("Missing value for myclass")

if __name__=="__main__":
    #oops, forgot to specify a parameter here !
    myobj=myclass()
    

Of course, I know I can always implement my own MissingValueError exceptions subclasses when writing a library. I am asking this question in order not to duplicate something that might already exist in the standard.

Community
  • 1
  • 1
Typhon
  • 291
  • 1
  • 2
  • 9
  • 1
    I don't think the Python standard exceptions cover this situation specifically, as it's a very scenario-specific situation. If I were you, I'd create my own exception to be thrown on construction of the object, or stick with the generic `Exception` class. – dddJewelsbbb Dec 16 '19 at 01:32
  • @dddJewelsbbb Is it really such a scenario specific situation ? The example I give is very specific of course, but the concept of a missing value seems to be appropriate in a variety of situations. – Typhon Dec 16 '19 at 01:43
  • See https://stackoverflow.com/questions/256222/which-exception-should-i-raise-on-bad-illegal-argument-combinations-in-python – Dan D. Dec 16 '19 at 01:46
  • 1
    @DanD. I would argue that this is a misuse of valueerror. https://docs.python.org/3/library/exceptions.html#ValueError clearly states that it's for values with "the right type". You can't check the type of a missing value. – Typhon Dec 16 '19 at 02:03
  • 1
    To make it clear, my distinction between the two, is that when you provide multiple default parameters, and you're checking that at least one is non-Falsy, or at least, not the default, your exception isn't that _you've provided the wrong type_, but that you _weren't given at least one of the sufficient types_, which I'd argue is a very subtle, but valid, difference between the two that makes this a "specific scenario". – dddJewelsbbb Dec 16 '19 at 04:22
  • 1
    But after thinking about it, maybe this is roughly a matter of perspective. I'd still argue that this should be a custom exception if we're concerned about throwing the "right one", but if you _must_ bubble a specific Python exception, I'd side with @lenik that the most appropriate would be `TypeError`, so long as you don't expect a falsy value. – dddJewelsbbb Dec 16 '19 at 04:29

2 Answers2

9

The proper exception would be TypeError:

>>> def a(b,c) : print b,c
... 
>>> a(1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: a() takes exactly 2 arguments (1 given)
>>> 

And as a side note, I'd recommend NOT to provide the default values to the required arguments, so the user of your class will clearly understand (s)he has to provide some.

lenik
  • 23,228
  • 4
  • 34
  • 43
0

You can also have your own custom validation exception.

Something like this:


class ValidationError(Exception):
    def __init__(self, msg):
        self.msg = msg


class MyClass(object):
    def __init__(self, firstparam=None, secondparam=None):
        if firstparam:
            self.firstinit()
        elif secondparam:
            self.secondinit()
        else:
            # What to put here ?
            raise ValidationError("Either firstparam or secondparam should be passed")

    def firstinit(self):
        pass

    def secondinit(self):
        pass


if __name__ == "__main__":
    #oops, forgot to specify a parameter here !
    try:
        myobj=MyClass()
    except ValidationError as err:
        print(err)

Output:

Either firstparam or secondparam should be passed
Shakeel
  • 1,869
  • 15
  • 23
  • 1
    I know I can create a custom exception, the purpose of this question was to ask whether there was already an exception in the standard library for this type of problem. – Typhon Sep 22 '21 at 08:23