如何使 __str__ 或 __repr__ 返回当前类的名称?

3

我有这段代码:

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

现在,当我尝试运行时

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

我只在一开始得到了“员工姓名”。如何更改它以反映“Hermoine”是一个Supervisor而不仅仅是一个Employee,而不需要重新编写__str____repr__方法?


2
说实话,我会在实例属性中明确指定“角色”,而不是尝试重用类名。在适当的__init__方法中添加self.role =“Employee”self.role =“Supervisor” - chepner
1
(或者在class语句命名空间中直接使用类属性role =“Employee”。) - chepner
1
@chepner,@U12-Forward建议的self.__class__.__name__方法是__repr__方法的一个非常常见的模式。例如,请参见collections.OrderedDictcollections.Countercollections.namedtuplecollections.ChainMap。https://github.com/python/cpython/blob/main/Lib/collections/__init__.py - Alex Waygood
1
这不是我喜欢的,特别是对于 str。对于仅用作调试工具的 repr 来说还好。对于 __str__,我宁愿使用显式数据而不是从 代码 推断出的值。 - chepner
1
好的,说得也有道理——但我认为值得注意的是,在标准库中定义__repr__方法通常是这样的,并且将__str__未定义(这意味着对__str__的调用将回退到__repr__方法)。我也不完全确定为什么您不认为类名是显式数据——在运行时动态设置或修改类名非常罕见。 - Alex Waygood
1个回答

9

解决方案:

尝试将您的第一个类更改为:

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"

尝试在所有字符串中使用 self.__class__.__name__ 代替 __class__.__name__
现在:
emp1 = Employee("Ron", 1000, "male")
emp10 = Supervisor("Hermoine", 3000, "female", "General")
print(emp1, emp10)

输出:

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

解释:

self返回实际类名的原因是它将从当前的self实例中提取类名。如果没有self,只会得到原始父类的类名,而不是它当前所在的实际类名,这就是为什么self非常重要的原因。

另外,正如@MadPhysicist所提到的那样,这是“因为__class__在类执行时具有词法作用域”。


4
因为__class__在类执行时被词法作用域封装:也就是说,它是一个硬编码的Emplpyee引用。 - Mad Physicist
1
@MadPhysicist 哦,好的!我已经把它加入到我的答案中了,感谢你的建议! - U13-Forward

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接