> On Nov 3, 2019, at 16:07, Anders Hovmöller <bo...@killingar.net> wrote:
> 
>> On 3 Nov 2019, at 13:31, Andrew Barnert <abarn...@yahoo.com> wrote:
>> 
>> On Nov 3, 2019, at 13:01, Anders Hovmöller <bo...@killingar.net> wrote:
>>> 
>>> Well, the last part requires that print can coerce bytes to str, not 
>>> strictly that it must do so via str(). repr() should return b'foo' but 
>>> str() could have returned <bytes object at 0x6363737>.
>> 
>> That would be very confusing.
> 
> 
> Why? Because you then say:
> 
>> When they differ, it’s always repr that returns something like <bytes object 
>> at 0x6363737>, as object.__repr__ gives. The only time you get that from str 
>> is on types without a __str__ method that fall back to __repr__.
> 
> And str of bytes deviate from this in that it returns what should be a repr, 
> not a str.

It doesn’t deviate. When they differ, it’s always repr that returns the 
angle-bracket format. When they don’t differ, they obviously don’t differ. 
Since bytes doesn’t differ, it follows that rule just fine.

The rules are pretty simple: (1) __repr__ returns either something eval-able if 
feasible or something angle-brackety if not; bytes follows this rule by 
returning something eval-able. (2) __str__ returns either something more 
human-readable if reasonable, or falls back to __repr__ if not; bytes follows 
this by falling back to __repr__.

Your proposal is to make __str__ return something _less_ human-readable, and, 
worse, something that looks like a repr. That would be confusing.

>> Objects that have a better representation for normal humans, even if it may 
>> be ambiguous or incomplete for programmers, use that for str, otherwise they 
>> just fall back to the repr.
> 
> Sure. But they don't have to. So that seems like it doesn't matter to the 
> discussion.  

It definitely does matter.

Python doesn’t prevent you from making __add__ multiply and __mult__ add, or 
making __reversed__ yield your elements in index order but __iter__ yield them 
in reverse order, or making __getitem__ delete the item and return None, or 
making __bool__ return True for an empty value and False for everything else. 
Likewise, it doesn’t prevent you from making __repr__ return a human-readable 
form and __str__ return something angle-brackety. That doesn’t mean it’s ever a 
good idea to do any of those things.

The rules are there to make code understandable to humans, to make your types 
useable by humans. Following them is a good idea except maybe in very unusual 
circumstances, and that’s even more true for a builtin type that’s used in 
millions of programs.

>> Also, this feature actually saved me time in a 2-to-3 port. A bunch of the 
>> code had been written by one of those people who puts str(x) all over the 
>> place even when x is already guaranteed to be a str, like buf = 
>> str(sock.recv(bufsize)). So there are bugs all over the place in 3.x, even 
>> after going through all the 2to3 flags and trying to guess what this call to 
>> str was meant to do. And being able to search the output and logs for “b'” 
>> worked just as well as being able to search for your “<bytes” would have, 
>> but the fact that we also got the actual bytes in that log made it easier to 
>> guess where it came from. (It helped that one main source of bytes was 
>> UTF-16, and the \0 after each ASCII byte is pretty easy to spot…)
> 
> Ah. Now finally an argument. Yes that was better than just <bytes...>. But if 
> str(bytes) raised and repr(bytes) did not and print(bytes) used repr(), then 
> you wouldn't have had to look at the bytes to guess where it came from, you'd 
> get a crash at the place where the problem was. Which would be much better!

No it wouldn’t. I know where the code is calling str; I don’t need an exception 
to tell me that. I often don’t know _why_ it’s doing that, and therefore I 
don’t know how to fix it; I need to see the bytes to tell me that.

There _are_ other cases where raising would actually be helpful. But that 
wasn’t your proposal anyway. You suggested that str(bytes) should return 
something that looks like a repr but isn’t, not that it should raise. The fact 
that there are some cases where str(bytes) raising would be helpful isn’t an 
argument for str(bytes) returning something different.

Meanwhile, changing print from “calls str on any args” to “calls repr on bytes 
but str on everything else” would make the function more complicated to learn 
and remember, and to implement and maintain. Maybe this special case is special 
enough, but I don’t think it is.

And breaking the fact that str almost never raises is a really bad idea. Think 
of all the times you’ve done quick&dirty debugging by printing out a bunch of 
intermediate variables. If that could raise and ruin your debug session, 
wouldn’t that be very frustrating? In fact, we don’t have to guess; anyone who 
ever used Python 2 on Windows, where printing out a unicode would often raise 
an encoding error instead of printing, can tell you how frustrating it was.

_______________________________________________
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/OY3GHA5HXDBYPY3DGRZY4IJ5BM3LBWEF/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to