On Feb 20, 2015, at 8:54 AM, Brett Cannon <brett@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:
str(uuid.uuid4()) 'd467d97c-fc09-4dc9-bea5-aeebdad8df8d’ str(int()) ‘0' str(datetime.datetime.now()) '2015-02-20 09:31:28.385539’ str(IPv4Address('127.0.0.1')) '127.0.0.1'
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>’ str(URLError('reason')) '<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.
* Demian Brecht <demianbrecht@gmail.com> [2015-02-20 10:24:53 -0800]:
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>’ str(URLError('reason')) '<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.
>>> foo = object() >>> str(foo) '<object object at 0x7f799a8a9070>' >>> repr(foo) '<object object at 0x7f799a8a9070>' This is exactly what you see above. ;) Florian -- http://www.the-compiler.org | me@the-compiler.org (Mail/XMPP) GPG: 916E B0C8 FD55 A072 | http://the-compiler.org/pubkey.asc I love long mails! | http://email.is-not-s.ms/
On Fri, Feb 20, 2015 at 12:36 PM, Florian Bruhin <me@the-compiler.org> wrote:
* Demian Brecht <demianbrecht@gmail.com> [2015-02-20 10:24:53 -0800]:
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>’ str(URLError('reason')) '<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.
>>> foo = object() >>> str(foo) '<object object at 0x7f799a8a9070>' >>> repr(foo) '<object object at 0x7f799a8a9070>'
This is exactly what you see above. ;)
Florian
-- http://www.the-compiler.org | me@the-compiler.org (Mail/XMPP) GPG: 916E B0C8 FD55 A072 | http://the-compiler.org/pubkey.asc I love long mails! | http://email.is-not-s.ms/
There's a semantic difference between an int and an IntEnum (or subclass thereof). MyEnum.FOO is a MyEnum type. IntEnums just happen to behave like an int under certain circumstances. That doesn't mean it needs to act like it in all. Further, it can be turned into an int if you want to represent it as an int, e.g., str(int(MyEnum.FOO)) == str(1). I hope this helps.
On Feb 20, 2015, at 7:03 PM, Ian Cordasco <graffatcolmingov@gmail.com> wrote: I hope this helps.
It does, as do the other replies, thanks all. To be clear, my first gripe has stemmed into two related (but very minor) problems: 1. IntEnum.__str__. I understand the reasoning behind the current implementation. Personally I’d still prefer it to be consistent with int (and other types as shown above) and if I wanted to know where it came from, I could use repr(), but I understand that this /was/ previously thought out and is contrary to the decision made. I’m fine with being in the minority (or on my own as it seems in this case) and leaving it alone (with the only caveat being the next point). 2. Consistency of __str__ semantics across the standard library and builtins. I believe that the value of __str__ is something that I, as a user, should be able to infer when using disparate types. Unfortunately, some represent the values while other represent the object themselves, nearly the same problem that __repr__ solves minus the requirement of being a valid Python expression where possible. In my mind, a clear separation between __str__ representing the value of an instance and __repr__ representing the object, or where the value came from (and perhaps /not/ having the auto-fallback) makes sense, but would only be one potential solution to promoting consistency. In any event, there are many larger problems to be solved (that is, if anyone else /does/ consider this a problem) and I very well may be on my own with this thinking.
On Sat, Feb 21, 2015 at 8:39 AM, Demian Brecht <demianbrecht@gmail.com> wrote:
On Feb 20, 2015, at 7:03 PM, Ian Cordasco <graffatcolmingov@gmail.com>
wrote:
I hope this helps.
It does, as do the other replies, thanks all. To be clear, my first gripe has stemmed into two related (but very minor) problems:
1. IntEnum.__str__. I understand the reasoning behind the current implementation. Personally I’d still prefer it to be consistent with int (and other types as shown above) and if I wanted to know where it came from, I could use repr(), but I understand that this /was/ previously thought out and is contrary to the decision made. I’m fine with being in the minority (or on my own as it seems in this case) and leaving it alone (with the only caveat being the next point).
You are indeed very much out of sync here. There is no requirement or even convention that int subclasses have the same str() as plain ints -- in fact a custom str() is a common reason. For example, it's one of the reasons why I eventually caved in and added bool to the language. People want the custom representation used when they say print(x), they don't want to have to say print(repr(x)).
2. Consistency of __str__ semantics across the standard library and builtins. I believe that the value of __str__ is something that I, as a user, should be able to infer when using disparate types. Unfortunately, some represent the values while other represent the object themselves, nearly the same problem that __repr__ solves minus the requirement of being a valid Python expression where possible. In my mind, a clear separation between __str__ representing the value of an instance and __repr__ representing the object, or where the value came from (and perhaps /not/ having the auto-fallback) makes sense, but would only be one potential solution to promoting consistency.
Again, this is an area where you are on your own looking for consistency. str() is what print() uses (by mutual definition) and print() should print whatever is the most useful as the default for a given use case. There is *no* rule that says a subclass cannot change the str().
In any event, there are many larger problems to be solved (that is, if anyone else /does/ consider this a problem) and I very well may be on my own with this thinking.
It sure seems that way. -- --Guido van Rossum (python.org/~guido)
On Feb 24, 2015, at 10:56 AM, Guido van Rossum <guido@python.org> wrote: It sure seems that way.
Thanks for the additional feedback Guido. I’d spent some further time thinking about what it was that I was looking for and determined it was bollocks. The proposal was a poor solution to a specific immediate problem without taking more general use cases into account. My apologies for the noise.
On 02/20/2015 10:24 AM, Demian Brecht wrote:
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).
There are two "stringy" methods for objects: __repr__ and __str__; if __str__ has not been defined __repr__ is automatically used. One of the motivating forces behind Enum is that often the name is more important (for humans) than the actual value, so __str__ is defined as being the Enum class name plus the Enum member name. The __repr__ has that as well as the underlying value (occasionally it's useful to know that, too ;) . -- ~Ethan~
participants (5)
-
Demian Brecht
-
Ethan Furman
-
Florian Bruhin
-
Guido van Rossum
-
Ian Cordasco