我应如何实现__hash__和__str__

4 投票
2 回答
1085 浏览
提问于 2025-04-17 01:23

我有一个叫做 WeakBoundMethod 的类(可以在 这里找到源代码)。我想知道应该怎么实现 __hash__() 这个方法。还有,Python 3 会自动提供一个 __repr__() 函数,所以我想我不需要重新定义它,对吧?那么 __str__() 呢,我知道这个是用来给人看得懂的文本表示,应该也要定义吗?有没有什么建议?

关于哈希函数……
我希望它能根据被包装的绑定方法的 __self____func__ 来生成哈希值。我该怎么做呢?

2 个回答

0

虽然我来得有点晚,但这个问题在搜索结果中排在前面,所以我想说几句。

关于:

另外,Python 3 自动提供了一个 repr() 函数,所以我想我不需要重新定义它了(?)。那么 str() 呢?我知道它是对象的可读文本表示;我也应该定义这个吗?有没有什么指导原则?

默认的实现方式在大多数情况下都可以用,但一旦你想要更有用的东西时,它们就不够用了。

举个例子:

class Message:
    _msg: str

    def __init__(self, msg: str):
        self._msg = msg

    # ... other custom behavior that makes this more useful than just a string


print(Message("asdf"))       # '<__main__.Wat object at 0x104a99128>'
print(str(Message("asdf")))  # '<__main__.Wat object at 0x104a991d0>'
print(repr(Message("asdf"))) # '<__main__.Wat object at 0x104a991d0>'

当然,默认的实现是存在的,但如果你有一些信息需要打印到屏幕、日志等地方,<module.class object at address> 这种格式真的有帮助吗?

再对比一下...

class Message:
    _msg: str
    _urgent: bool

    def __init__(self, msg: str, urgent:bool = False):
        self._msg = msg
        self._urgent = urgent

    @classmethod
    def urgent(cls, msg: str) -> "Message":
        return cls(msg, urgent=True)

    def __str__(self) -> str:
        if not self._urgent:
            return self._msg

        return f"URGENT: {self._msg.upper()}"

    def __repr__(self) -> str:
        return f"{type(self).__name__}({self})"

    # ... other custom behavior that makes this more useful than just a string


print(Message("hey there!"))                   # hey there!
print(str(Message("hey there!")))              # hey there!
print(str(Message.urgent("look behind you")))  # URGENT: LOOK BEHIND YOU
print(repr(Message.urgent("look behind you"))) # Message(URGENT: LOOK BEHIND YOU)

上面的建议“如果不确定,就不要实现魔法方法。”部分是对的(如果你不需要这个功能,那为什么要实现呢?),但这也似乎暗示你可能不应该去做。其实,魔法方法是为了被重写的——这就是我们如何让自己的类拥有一些Python内置的有用功能,避免写很多冗余的代码,比如将对象转成字符串、创建自定义的迭代器或上下文管理器等等。

2

如果不确定,就不要实现魔法方法。默认的设置是有原因的,通常是可以满足需求的。在你的情况下,完全没有必要去实现 __hash__(而且如果你要实现它,你还得实现 __eq__),除非你希望有人使用一个包含方法的集合或字典。

__str__ 方法是有用的。在你的情况下,它的结果应该包括:

  • 类的名称,以避免与其他东西混淆
  • 这个函数是否还在运行
  • 如果它还在运行,显示它的 str() 结果,以便通过名称来识别这个函数

撰写回答