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

This post is about one of the type errors that occur when using functions or methods in Python.

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 X positional argument but Y were given

__init__ method:

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

Other methods of the class:

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

What does the error message mean?

In short, this error message means that the arguments you are passing do not match the parameters of a function.

The error message contains a hint that the function accepts a certain number of arguments (X), but a different number of arguments (Y) was given when the function was called.

See this post if you have an error in the __init__ method and the error message is TypeError: __init__() takes 1 positional argument but X were given or TypeError: MyClass.__init__() takes 1 positional argument but X were given.


Inconsistent Arguments and Parameters

The number of arguments (values) passed to the function must match the number of parameters in the function signature.

def function(param1, param2): # <-- two parameters
    pass

# two arguments passed - OK
function("some value", "other value")

# three arguments passed - this will throw a TypeError!
function("some value", "other value", "excess")
# TypeError: function() takes 2 positional arguments but 3 were given

The same goes for class methods.

class A:
    def __init__(self, param2): # <-- two parameters
        pass

# two arguments passed - self and "value" - OK
a = A("value")

# three arguments passed - this will throw a TypeError!
a = A("value", "excess")
# TypeError: function() takes 2 positional arguments but 3 were given

A special feature of the class method is the presence of the mandatory parameter "self". Although we don't need to explicitly pass a value for this parameter, its value is still included in the number of positional arguments.


Functions may take no arguments at all.

def function(): # <-- no parameters
    pass

# no arguments passed - OK
function()

# argument passed - this will throw a TypeError!
function("excess argument")
# TypeError: function() takes 0 positional arguments but 1 were given

Class methods take at least one argument: value for self.

class A:
    def __init__(self):
        pass
    def do(self): # <-- one parameter
        pass

# args: the current instance of the class
a = A()

# two arguments passed - this will throw a TypeError!
# args: the current instance of the class and "excess argument"
a.do("excess argument")
# TypeError: A.do() takes 1 positional argument but 2 were given

Cases With Keyword Arguments

The error may occur when the function/method accepts only X positional arguments, all other arguments are keyword arguments.

A keyword argument means that the parameter must be associated with a value when the function is called. E.g., function(param=value).

The use of keyword arguments in a function can be made mandatory by adding special characters to the signature. We can use an asterisk (*) in the named parameter list or add **kwargs to indicate that the function can take arbitrary keyword arguments.

Examples with functions

def function(param1, *, param2): # param2 is a keyword-only parameter
    pass

# one positional argument and one keyword argument - OK
function("some value", param2="other value")

def function(param1, **kwargs):
    pass

# one positional argument and one keyword argument - OK
function("some value", param2="other value")

Examples with classes

The same keyword arguments apply to class methods. The first positional argument is always an instance of the class (the value for the self parameter). But we don't need to explicitly pass this to the methods. All parameters after the asterisks are keyword-only parameters. Therefore, we must use keyword arguments.

class A:
    def __init__(self, *, param2):
        pass
    def do(self, param2, *, param3):
        pass

a = A(param2="value")
a.do("some value", param3="other value")

**kwargs can also be used in class methods.

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

a = A(param2="value")
a.do("some value", param3="other value")

Popular posts from this blog

Tkinter Button Widget