TypeError: __init__() missing 3 required positional arguments

avatar

Borislav Hadzhiev

Wed Apr 20 20223 min read

banner

Photo by Ken Cheung

TypeError: __init__() missing 3 required positional arguments #

The Python "TypeError: __init__() missing 3 required positional arguments" occurs when we forget to provide 3 required arguments when instantiating a class. To solve the error, specify the arguments when instantiating the class or set default values for the arguments.

typeerror init missing 3 required positional arguments

Here is an example of how the error occurs.

main.py
class Employee(): # 👇️ takes `name`, `salary` and `department` args def __init__(self, name, salary, department): self.name = name self.salary = salary self.department = department def get_name(self): return self.name # ⛔️ TypeError: Employee.__init__() missing 3 required positional arguments: 'name', 'salary', and 'department' emp1 = Employee()

We tried instantiating the Employee class but didn't provide a value for the name, salary and department arguments which caused the error.

One way to solve the error is to provide a value for the arguments.

main.py
class Employee(): def __init__(self, name, salary, department): self.name = name self.salary = salary self.department = department def get_name(self): return self.name # ✅ provide values when instantiating class emp1 = Employee('Alice', 100, 'dev') print(emp1.name) # 👉️ "Alice" print(emp1.salary) # 👉️ 100 print(emp1.department) # 👉️ "dev"
When we instantiate a class, we should provide all the arguments that we have specified in the classes' __init__() method (other than self which is passed automatically).

When a class defines the __init__() method, the method is invoked when an instance is created.

If your class doesn't define an __init__() method, you don't have to pass any arguments when instantiating it.

If you pass arguments when instantiating a class, the arguments are passed on to the __init__() method.

An alternative solution is to set default values for the arguments.

main.py
class Employee(): def __init__(self, name='', salary=0, department=''): self.name = name self.salary = salary self.department = department def get_name(self): return self.name emp1 = Employee() print(emp1.name) # 👉️ "" print(emp1.salary) # 👉️ 0 print(emp1.department) # 👉️ ""

We set an empty string as the default value for the name and department arguments and 0 as the default value for the salary argument.

Note that you can also use None values if you can't think of a good default value.

Now, we aren't required to provide a value for the arguments when instantiating the class.

Note that the first argument the __init__() method takes is self.

You could name this argument anything because the name self has no special meaning in Python.

self represents an instance of the class, so when we assign a variable as self.my_var = 'some value', we are declaring an instance variable - a variable unique to each instance.

If you are just hard coding an initial value for the arguments in the __init__() method, you can remove it and hardcode the values in the method.
main.py
class Employee(): def __init__(self): self.name = "Alice" self.salary = 100 self.department = 'dev' def get_name(self): return self.name emp1 = Employee() print(emp1.name) # 👉️ "Alice" print(emp1.salary) # 👉️ 100 print(emp1.department) # 👉️ "dev"

We hardcoded the value for the name instance variable and set it to Alice.

Now every new instance is going to have a name attribute set to Alice.

You can update the value for the attribute later on in your code, e.g. emp1.name = 'Bob'.

An important note is to avoid setting default values for non-primitive arguments, e.g. dictionaries and lists.

Here is an example of how this can go wrong.

main.py
class Employee(): # 👇️ default arg of type dict def __init__(self, address={}): self.address = address emp1 = Employee() emp2 = Employee() emp1.address['country'] = 'Germany' print(emp1.address['country']) # 👉️ "Germany" print(emp2.address['country']) # 👉️ "Germany"

We created 2 instances, updated the address in 1, but the change is reflected in both instances.

This is because default arguments are only evaluated once - when the function is defined.

They are not evaluated each time the function is called.

When a non-primitive default argument like a dictionary or list is mutated, it is mutated for all function calls.

One way to get around this issue is to set the default argument to None and conditionally update its value in the body of the function.

main.py
class Employee(): def __init__(self, address=None): self.address = address if address is None: self.address = {} emp1 = Employee() emp2 = Employee() emp1.address['country'] = 'Germany' print(emp1.address['country']) # 👉️ "Germany" print(emp2.address['country']) # 👉️ KeyError: 'country'

The body of the method is ran every time it is invoked, so the issue no longer exists.

Use the search field on my Home Page to filter through my more than 1,000 articles.