开发者

How should I implement __hash__ and __str__

I have a class called WeakBoundMethod (source on codereview.se). I'd like some guidelines about how I should implement __hash__(). Also, Python 3 automatically provides a __repr__() function, so I guess I shouldn't bother redefining it then (?). What about __str__(), which I u开发者_C百科nderstand is a human readable text representation of the object; should I define that as well? any guidelines?

About the hashing function...

I'd like it to generate the hash based on the __self__ and __func__ of the bound method it is wrapping. How can I do that?


If in doubt, don't implement magic methods. The defaults are there for a reason and will be fine. In your case, it's completely unnecessary to implement __hash__ (and if you would implement it, you'd have to implement __eq__ as well) unless you expect someone to have a set or dictionary of methods.

__str__ can be useful. In your case, its result should include:

  • The class name, to avoid confusion with anything else
  • Whether the function is alive or not
  • If it is alive, its str() result to identify the function, say, by name


9 years late to the party, but since this came up at the top of search results for me...

Regarding:

Also, Python 3 automatically provides a repr() function, so I guess I shouldn't bother redefining it then (?). What about str(), which I understand is a human readable text representation of the object; should I define that as well? any guidelines?

The default implementations are fine until they aren't (ie. until you want something more useful).

Case in point:

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>'

Sure, the defaults exist, but if you have something that's helpful to print to screen, logs, etc. is the <module.class object at address> format really helpful?

Contrast that with...

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)

The advice above, "If in doubt, don't implement magic methods." is partially true (if you don't need functionality, why implement it?) but it also seems to indicate that you probably shouldn't. Magic methods are actually meant to be overwritten - it's how we enrich our classes with useful behavior that is 'built in' to Python and avoid a lot of otherwise necessary boilerplate to serialize to strings, create custom iterators or context managers, etc.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜