1

So I have a function like:

def my_code(arg1, *args):
    ....

And I want this function to only be able to take either 2 or 3 arguments (that means *args can only be 1 or 2 arguments). How do I throw an error message if the number of arguments is wrong? If I use a try/exception, is there a specific exception type for this?

  • You should raise `TypeError`. – heemayl Mar 15 '18 at 21:23
  • If you want to only take 2 or 3 arguments, it sounds like it may be better to define the function as `def func(arg1, arg2, arg3=None)`, or to write two functions. – user2357112 Mar 15 '18 at 21:25
  • The way to figure this out yourself is to write a function that takes two parameters, call it with one argument or four, and see what exception gets raised. You want to raise the same exception, with similar text (but maybe more informative—the exact text doesn't matter. just the exception type). – abarnert Mar 15 '18 at 21:26

4 Answers4

3

You can get the length of args with len as you would for any tuple.

def my_code(arg1, *args):
    if not 0 < len(args) < 3:
        raise TypeError('my_code() takes either 2 or 3 arguments ({} given)'
                        .format(len(args) + 1))

my_code(1) # TypeError: my_code() takes either 2 or 3 arguments (1 given)
my_code(1, 2) # pass
my_code(1, 2, 3) # pass
my_code(1, 2, 3, 4) # TypeError: my_code() takes either 2 or 3 arguments (4 given)
Olivier Melançon
  • 21,584
  • 4
  • 41
  • 73
  • 2
    To bring the error inline with the builtin argument checking, I would suggest `raise TypeError('my_code() takes either 2 or 3 arguments (%d given)' % (len(args) + 1))` – TemporalWolf Mar 15 '18 at 22:19
  • If you really want to get fancy, you can `import sys` and use [`sys._getframe().f_code.co_name`](https://stackoverflow.com/a/13514318/3579910) to programmatically pull the function name... although that's probably overkill depending on the size of the project. – TemporalWolf Mar 15 '18 at 22:43
  • I think you can actually do simpler with inspect: `inspect.stack()[0][3]` – Olivier Melançon Mar 15 '18 at 22:46
0

Your test is:

if len(args) not in (1,2):

though there are of course other ways to phrase that.

As for the exception, if you call a built-in function with the wrong number of arguments, you get a TypeError. If your application doesn't justify creating your own subclass of Exception, then that is probably the way to go.

BoarGules
  • 16,440
  • 2
  • 27
  • 44
0
def my_code(*args):
    if len(args) > 2:
        raise TypeError
    else:
        # code for your function
        pass

Basically *args is a tuple, and if you want a maximum number of arguments you can raise a TypeError.

S.B
  • 13,077
  • 10
  • 22
  • 49
dejanualex
  • 3,872
  • 6
  • 22
  • 37
0

I'm facing a similar problem. I think the ValueError is better suited for this.

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

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

I have a function that can receive two arguments, but should receive only either one of the two, but not both. If both are set, or none of them are set, it's a problem. I use the ValueError exception for this.

Example code:

def parse_article(self, url: string = None, file: string = None) -> Article:
        if url == None and file == None:
            raise ValueError("Function was called without any arguments. Please set either url or file, but not both.")
        else:
            if url != None and file != None: raise ValueError(
                "Both url and file were given. Please give either url or file, but not both.")
        # Rest of the function.
        # Parse the article at the url or in the file, then return it.
Tamas K
  • 96
  • 4