Python class showing "missing 1 required positional argument: 'self'"

12.2k Views Asked by At

I was making a python class in which it has an employee's name, salary, and the number of leaves as attributes and was trying to show the final salary of an employee deducting the salary for the days he/she has not come but it is showing an error. The error is:

    TypeError: Employee.f_salary() missing 1 required positional argument: 'self'
      

I had written the code:

class Employee:
    def __init__(self, name, salary, no_of_leaves):
        self.name = name
        self.salary = salary
        self.no_of_leaves = no_of_leaves

    def f_salary(self):
        self.f_salary1 = self.salary - 500 * int(self.no_of_leaves)

    def display(self):
        print(f"Employee's name: {self.name}\nEmployee's monthly salary: 
        {self.salary}\nNo.of leaves that employee has taken: {self.no_of_leaves}")

nol = input("No. of leaves the employee has taken: ")

john_smith = Employee('John Smith', 182500, nol)

Employee.f_salary()
Employee.display()
3

There are 3 best solutions below

0
Bemwa Malak On BEST ANSWER

You should call the method on the instance not the class object.

john_smith.f_salary()
john_smith.display()

Because the self parameter is a reference to the class instance which called the method in the first place.

1
Locke On

The issue is you call the method on the class instead of the object you created.

Employee.f_salary()
Employee.display()

This can be easily fixed by using the object name.

john_smith.f_salary()
john_smith.display()

You can however pass self explicitly though if you use the class to call a method.

class Foo:
    def bar(self):
        # Etc.

some_foo = Foo()

# These are more or less equivalent if we assume no class extends Foo
Foo.bar(some_foo)
some_foo.bar()
0
chepner On

Instance methods are just class attributes. Employee.f_salary is a reference to a function that requires a single argument.

john_smith.f_salary, though, is more interesting. Because function objects implement the descriptor protocol, accessing the value as an attribute of something always triggers its __get__ method, so that

Employee.f_salary == Employee.__dict__['f_salary'].__get__(None, Employee)
john_smith.f_salary == Employee.__dict__['f_salary'].__get__(john_smith, Employee)

In the first case, __get__ simply returns the function itself, so when you try to call it, it still expects an argument for its self parameter.

In the second case, __get__ returns an instance of the method class, which internally keeps two references: one to john_smith, and one to the function itself.

When you try to call the method object, it simply takes its own arguments and passes them, along with john_smith, to the underlying function.

As such, john_smith.f_salary() returns the value of Employee.f_salary(john_smith).