> On Feb 20, 2015, at 8:54 AM, Brett Cannon <brett(a)python.org> wrote:
> Concrete reason. The string is 'MyEnum.FOO' which is much more readable and obvious where the value came from. The fact that it can be treated as an int is the same as the reason True and False are subclasses of int; it made practical sense for compatibility with what they typically replaced, but where it made more sense to diverge and introduce new behaviour then we did so.
Thanks Brett, that makes sense and was pretty much what I assumed. Reading the docs for __str__ does clarify things a bit in that the intention is to be a string representation of the object and not the value. That said, implementations seem to vary throughout the standard library and builtins:
These and other implementations return a string representation of the instance’s value, not a string representation of the object itself. Whereas elsewhere in the standard library:
>>> str(ProtocolError('url', 42, 'msg', ''))
'<ProtocolError for url: 42 msg>’
'<urlopen error reason>’
>>> str(Cookie(0, '', '', '4', '', '', '', '', '', '', '', 0, '', '', '', ''))
'<Cookie = for :4>'
The specific problem that I encountered was when swapping an IntEnum implementation for ints in http.client, which caused a change in logging output (from int.__str__ to Enum.__str__), which was a bit of a surprise, especially given the value is a builtin type.
I think that a decent rule around the usage of __str__ is that it should be a string representation of the value, not of the object. Failing the ability to logically coerce the value to a string, it should simply fall back to repr(obj).
Of course, I realize that the chances of this change being made to such a fundamental (and largely inconsequential) feature are likely nil, but I thought I’d share my thoughts anyways.