20-25 years ago this might have been a good idea. Unfortunately there's so much code (including well-publicized example code) that I'm not sure it's a good use of anyone's time to try and fix this.

Exception: I am often in need of a constructor for a bytes object from an integer using the decimal representation, e.g. bytes.fromint(42) == b"42". (Especially when migrating code from Python 2, where I've found a lot of str(n) that cannot be translated to bytes(n) but must instead be written as b"%d" % n, which is ugly and unintuitive when coming from Python 2.)

On Mon, May 6, 2019 at 2:50 AM Serhiy Storchaka <storchaka@gmail.com> wrote:
Constructors for builtin types is too overloaded.

For example, int constructor:

* Converts a number (with truncation) to an integer.
* Parses human readable representation of integer from string or
bytes-like object. Optional base can be specified. Note that there is an
alternate constructor for converting bytes to int using other way:
int.frombytes().
* Without arguments returns 0.

str constructor:

* Converts an object to human-readable representation.
* Decodes a bytes-like object using the specified encoding.
* Without arguments returns an empty string.

bytes constructor:

* Converts a bytes-like object to a bytes object.
* Creates a bytes object from an iterable if integers.
* Encodes a string using the specified encoding. The same as str.encode().
* Creates a bytes object of the specified length consisting of zeros.
Equals to b'\0' * n.

dict constructor:

* Creates a dict from a mapping.
* Creates a dict from an iterable of key-value pairs.
* Without arguments returns an empty dict.

The problem of supporting many different types of input is that we can
get wrong result instead of error, or that we can get error later, far
from the place where we handle input.

For example, if our function should accept arbitrary bytes-like object,
and we call bytes() on the argument because we need the length and
indexing, and we pass an integer instead, we will get an unexpected
result. If our function expects a number, and we call int() on the
argument, we may prefer to get an error if pass a string.

I suggest to add limited versions of constructors as named constructors:

* int.parse() -- parses string or bytes to integer. I do not know
whether separate int.parsestr() and int.parsebytes() are needed. I think
round(), math.trunc(), math.floor() and math.ceil() are enough for lossy
converting numbers to integers. operator.index() should be used for
lossless conversion.
* bytes.frombuffer() -- accepts only bytes-like objects.
* bytes.fromvalues() -- accepts only an iterable if integers.
* dict.frommapping() -- accepts only mapping, but not key-value pairs.
Uses __iter__() instead of keys() for iterating keys, and can take an
optional iterable of keys. Equals to {k: m[k] for k in m} or {k: m[k]
for k in keys}.
* dict.fromitems() -- accepts only key-value pairs. Equals to {k: v for
k, v in iterable}.

_______________________________________________
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


--
--Guido van Rossum (python.org/~guido)
Pronouns: he/him/his (why is my pronoun here?)