TypeError: function() takes from 1 to X positional arguments but Y were given

This post is about one of the type errors that occur when using parameters with default values in functions and methods.

Table of Contents

For more information about argument types and parameter types, see Argument Types in Python Functions, Parameter Types in Python Functions.


Explanation of the Error

This type of error can occur both in standalone functions and in class methods that are also functions.

Function:

...
    function(<some arguments here>)
TypeError: function() takes from 1 to X positional arguments but Y were given

__init__ method:

...
    class_instance = MyClass(<some arguments here>)
TypeError : MyClass.__init__() takes from 1 to X positional arguments but Y were given

Other methods of the class:

...
    class_instance.method(<some arguments here>)
TypeError: MyClass.method() takes from 1 to X positional arguments but Y were given

What does the error message mean?

This error is common for functions whose parameters have default values. When there are defaults, there is no need to pass all the arguments to the function. Therefore, the error message indicates the range of the number of arguments, not a specific number.

There are two typical cases when this TypeError occurs:

In the first case, you passed too many arguments to the function. The solution in this case is to make sure the number of arguments matches the number of function parameters.

In the second case, part of the function arguments must be only keyword arguments. Such arguments are passed to the function in the form parameter=value.


Cases Where There Are More Positional Arguments Than Necessary

In the following examples, when we call a function, we pass more positional arguments to it than we should.


An example with a function

Here it is obvious that the extra argument leads to an error.

def function(param1, param2=True):
    pass
    
function("value", False, "excess")
# TypeError: function() takes from 1 to 2 positional arguments but 3 were given

Examples with classes

class A:
    def __init__(self, param2, param3=True):
        pass

a = A("value", False, "excess")
# TypeError: A.__init__() takes from 2 to 3 positional arguments but 4 were given

Let's count our parameters and arguments: self - class instance, param2 - "value", param3 - True or False by choice, ? - "excess".

"excess" is the fourth positional argument, which should not be here. This argument has no matching parameter.


Cases With Keyword Arguments

The function may accept arguments only in the form of a parameter=value pair. This can be done in two ways. A function signature may contain an asterisk (*) and/or **kwargs.


Examples with a function

In the following example, the second argument (False) is not redundant. You just need to pass it correctly to the function.

def function(param1=None, *, param2=True):
    pass
    
function("value", False)
# TypeError: function() takes from 0 to 1 positional arguments but 2 were given

This 1 positional argument in the error message is param1. Since param1 has a default value, the number of positional arguments passed to the function can be 0.

The function takes a maximum of 1 positional argument, the second must be a keyword argument. All arguments that match parameters specified after an asterisk (*) must be keyword arguments.

Should be:

function("value", param2=False)

The next example shows a case where arbitrary keyword arguments can be provided (**kwargs).

def function(param1="value", **kwargs):
    pass
    
function("other value", 10)
# TypeError: function() takes from 0 to 1 positional arguments but 2 were given

As in the previous example, the positional argument here can only be param1. Except for the first argument, all arguments must be keyword arguments in this example.

function("other value", param2=10)

Examples with a class

An error can occur when a class method takes 1 to X positional arguments, all other arguments are keyword arguments.

class A:
    def __init__(self, param2="value", *, param3=True):
        pass

a = A("other value", False)
TypeError: A.__init__() takes from 1 to 2 positional arguments but 3 were given
The first positional argument in class methods is always an instance of the class (self). The second positional argument here is param2. There must be one keyword argument, param3=False. All arguments that match parameters specified after an asterisk (*) must be keyword arguments.

Should be:

a = A("other value", param3=False)

**kwargs can also be used in class methods.

class A:
    def __init__(self, param2=True, **kwargs):
        pass

a = A(False, "value")
TypeError: A.__init__() takes from 1 to 2 positional arguments but 3 were given

Except for the first two arguments, all arguments should be keyword arguments in this example. The instance of the class (the value for the self parameter) is the very first argument. The second argument is False. So param3 is the keyword argument.

a = A(False, param3="value")

Popular posts from this blog

Tkinter Button Widget