Search code examples
pythonpython-3.xclasspython-class

How can I make __str__ or __repr__ return the current class's name?


I have this code:

class Employee:
    def __init__(self, name, pay, gender):
        self.name = name
        self.pay = pay
        self.gender = gender

    def add_raise(self):
        self.pay = int(self.pay*1.10)

    def __str__(self):
        if self.gender == "Female" or self.gender == "female":
            return f"{__class__.__name__} name: {self.name}, and she earns {self.pay} Pound"
        else:
            return f"{__class__.__name__} name: {self.name}, and he earns {self.pay} Pound"

    def __repr__(self):
        if self.gender == "Female" or self.gender == "female":
            return f"{__class__.__name__} name: {self.name}, and she earns {self.pay} Pound"
        else:
            return f"{__class__.__name__} name: {self.name}, and he earns {self.pay} Pound"

class Supervisor(Employee):
    def __init__(self, name, pay, gender, department):
        super().__init__(name, pay, gender)
        self.department = department

Now, when I try to run

emp1 = Employee("Ron", 1000, "male")
emp10 = Supervisor("Hermoine", 3000, "female", "General")
print(emp1, emp10)

I only get "Employee name" at the beginning. How do I change it so it reflects that "Hermoine" is a Supervisor and not just an Employee, without re-writing both the __str__ and __repr__ methods?


Solution

  • Solution:

    Try changing your first class to:

    class Employee:
        def __init__(self, name, pay, gender):
            self.name = name
            self.pay = pay
            self.gender = gender
    
        def add_raise(self):
            self.pay = int(self.pay*1.10)
    
        def __str__(self):
            if self.gender == "Female" or self.gender == "female":
                return f"{self.__class__.__name__} name: {self.name}, and she earns {self.pay} Pound"
            else:
                return f"{self.__class__.__name__} name: {self.name}, and he earns {self.pay} Pound"
    
        def __repr__(self):
            if self.gender == "Female" or self.gender == "female":
                return f"{self.__class__.__name__} name: {self.name}, and she earns {self.pay} Pound"
            else:
                return f"{self.__class__.__name__} name: {self.name}, and he earns {self.pay} Pound"
    

    Try self.__class__.__name__ instead of __class__.__name__ in all strings.

    And now:

    emp1 = Employee("Ron", 1000, "male")
    emp10 = Supervisor("Hermoine", 3000, "female", "General")
    print(emp1, emp10)
    

    Output:

    Employee name: Ron, and he earns 1000 Pound Supervisor name: Hermoine, and she earns 3000 Pound
    

    Explanation:

    The reason why self returns the actual class name is because it will extract the class name from the current self instance. Without self would only get the class name of the original parent class, not the actual class it's currently in, that's the reason self is so important.

    Also as @MadPhysicist mentioned, it's "because __class__ is lexically scoped at class execution time".