我应如何实现__hash__和__str__
我有一个叫做 WeakBoundMethod 的类(可以在 这里找到源代码)。我想知道应该怎么实现 __hash__()
这个方法。还有,Python 3 会自动提供一个 __repr__()
函数,所以我想我不需要重新定义它,对吧?那么 __str__()
呢,我知道这个是用来给人看得懂的文本表示,应该也要定义吗?有没有什么建议?
关于哈希函数……
我希望它能根据被包装的绑定方法的 __self__
和 __func__
来生成哈希值。我该怎么做呢?
2 个回答
虽然我来得有点晚,但这个问题在搜索结果中排在前面,所以我想说几句。
关于:
另外,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内置的有用功能,避免写很多冗余的代码,比如将对象转成字符串、创建自定义的迭代器或上下文管理器等等。
如果不确定,就不要实现魔法方法。默认的设置是有原因的,通常是可以满足需求的。在你的情况下,完全没有必要去实现 __hash__
(而且如果你要实现它,你还得实现 __eq__
),除非你希望有人使用一个包含方法的集合或字典。
__str__
方法是有用的。在你的情况下,它的结果应该包括:
- 类的名称,以避免与其他东西混淆
- 这个函数是否还在运行
- 如果它还在运行,显示它的
str()
结果,以便通过名称来识别这个函数