On Sun, Dec 15, 2019 at 6:09 AM Serhiy Storchaka <storchaka@gmail.com> wrote:
Currently str() takes up to 3 arguments. All are optional and
positional-or-keyword. All combinations are valid:

str()
str(object=object)
str(object=buffer, encoding=encoding)
str(object=buffer, errors=errors)
str(object=buffer, encoding=encoding, errors=errors)
str(encoding=encoding)
str(errors=errors)
str(encoding=encoding, errors=errors)

The last three are especially surprising. If you do not specify an
object, str() ignores values of encoding and errors and returns an empty
string.

bytes() and bytearray() are more limited. Valid combinations are:

bytes()
bytes(source=object)
bytes(source=string, encoding=encoding)
bytes(source=string, encoding=encoding, errors=errors)

I propose several changes:

1. Forbids calling str() without object if encoding or errors are
specified. It is very unlikely that this can break a real code, so I
propose to make it an error without a deprecation period.

What problem are you trying to solve with this proposal? I am only -0 on this, but I am wondering why bother with the churn.
 
2. Make the first parameter of str(), bytes() and bytearray()
positional-only. Originally this feature was an implementation artifact:
before 3.6 parameters of a C implemented function should be either all
positional-only (if used PyArg_ParseTuple), or all keyword (if used
PyArg_ParseTupleAndKeywords). So str(), bytes() and bytearray() accepted
the first parameter by keyword. We already made similar changes for
int(), float(), etc: int(x=42) no longer works.

I am +1 on this. Your reasoning is spot on. (Note that str() must work -- all builtin types can be called without arguments and will return a "zero" element of the right type.)
 
Unlikely str(object=object) is used in a real code, so we can skip a
deprecation period for this change too.

Likely.
 
3. Make encoding required if errors is specified in str(). This will
reduce the number of possible combinations, makes str() more similar to
bytes() and bytearray() and simplify the mental model: if encoding is
specified, then we decode, and the first argument must be a bytes-like
object, otherwise we convert an object to a string using __str__.

 I'm -0 on this. It seems that the presence of either errors= or encoding= causes str() to switch to "decode bytes" semantics, and a default decoding of UTF-8. That default makes sense: UTF-8 is our default source encoding, and we are trending to use it as the default in other places. I doubt that such calls would confuse anyone.

--
--Guido van Rossum (python.org/~guido)