
So can we just finish PEP 584 without the .copy() call? Surely the more general solution will not be ready for Python 3.9, while PEP 584 is nearly done. (I'm also skeptical about a general solution, but I'd rather stay out of that discussion for a while longer, and maybe you all come up with something good.) On Sun, Feb 16, 2020 at 8:46 AM Brandt Bucher <brandtbucher@gmail.com> wrote:
After a few days of thinking and experimenting, I’ve been convinced that `copy` (and also `__copy__`) is not the right protocol for what we want to do here. I believe that 584 can likely continue without subclass-preserving behavior, but that better behavior could perhaps could be added to *all* built-in types later, since it’s outside the scope of this PEP.
My opinion is that Python built-in types make subclassing unnecessarily(?) awkward to use, and I would like to see that change.
Yes! But, on further reflection, I don’t think this is the correct way of approaching it.
For example, consider subclassing float. If you want your subclass to be actually usable, you have to write a whole bunch of boilerplate, otherwise the first time you perform arithmetic on your subclass, it will be converted to a regular old float… This is painful and adds a great amount of friction to subclassing.
`float` is a *perfect* example of the problems with the way things are currently, so let’s focus on this.
Currently, subclassing `float` requires ~30 overridden methods of repetitive (but non-trivial) boilerplate to get everything working right. However, calling the `float` equivalent of `dict.copy()` on the LHS before proceeding with the default implementation wouldn’t help us, because floats (like many built-in types) are immutable. So a new, plain, built-in `float` would still be returned by the default machinery. It doesn’t know how to construct a new, different instance of our subclass, and it can’t change one it’s already built.
This leads me to believe that we’re approaching the problem wrong. Rather than making a copy and working on it, I think the problem would be better served by a protocol that runs the default implementation, *then* calls some under hook on the subclass to build a new instance.
Let’s call this method `__build__`. I’m not sure what its arguments would look like, but it would probably need at least `self`, and an instance of the built-in base class (in this case a `float`), and return a new instance of the subclass based on the two. It would likely also need to work with `cls` instead of `self` for `classmethod` constructors like `dict.fromkeys`, or have a second hook for that case.
By subclassing `float` and defining `__build__` to something like this:
``` class MyFloat(float): … def __build__(self, result): Return MyFloat(result, some_state=self.some_state) … ```
I could now trust the built-in `float` machinery to try calling `lhs.__build__(result)` on the result that *would* have been returned *before* returning it. This is a simple example, but a protocol like this would work for mutables as well.
A more pertinent example, from dict itself:
If `dict` *were* to grow more operators, they would likely be `^`, `&`, and `-`. You can consider the case of subclassing `set` or `frozenset`, since they currently has those. Calling `lhs.copy()` first before updating is fine for additive operations like `|`, but for subtractive operations like the others, this can be very bad for performance, especially if we’re now *required* to call them. Again, doing things the default way, and *then* constructing the appropriate subclass in an agreed-upon way seems like the path to take here.
Changing all builtins is a big, backwards-incompatible change.
If implemented right, a system like the one described above (`__build__`) wouldn’t be backward-incompatible, as long as nobody was already using the name.
Just food for thought. I think this is a much bigger issue than PEP 584, but I'm convinced that the consistent status quo should prevail until a suitable solution for all types can be worked out (if ever). _______________________________________________ Python-Dev mailing list -- python-dev@python.org To unsubscribe send an email to python-dev-leave@python.org https://mail.python.org/mailman3/lists/python-dev.python.org/ Message archived at https://mail.python.org/archives/list/python-dev@python.org/message/7HNJ6RVV... Code of Conduct: http://python.org/psf/codeofconduct/
-- --Guido van Rossum (python.org/~guido) *Pronouns: he/him **(why is my pronoun here?)* <http://feministing.com/2015/02/03/how-using-they-as-a-singular-pronoun-can-c...>