[Python-3000] Nix dict.copy()

Guido van Rossum guido at python.org
Tue Feb 12 18:56:58 CET 2008


On Feb 11, 2008 10:20 PM, Raymond Hettinger <python at rcn.com> wrote:
> >> I don't think we'll ever get another chance to clean-up the mapping API and to remove duplicate functionality (the code for
> >> dict.__copy__ and dict.copy share the same implementation).
> >
> > I find the use of a copy operation that purports to copy any object
> > suspect (regardless whether it's a module or a builtin), and that I'd
> > rather have a copy() method on the MutableMapping API.
>
> Should I revert the -3 warning on copy() methods that I checked-in a few days ago?

Yes, I think we jumped the gun here a bit.

> > I think my objection against the fully generic copy operation is that
> > it's type is useless -- all we know that it is supposed to return the
> > same type as its argument, but our type system can't express that.
>
> I'm not sure I follow you here.  The definition of Iterator.__iter__
> is to return self, so it doesn't seem like much of a leap to express
> a signature with a return type of type(self).

Actually, __iter__ is defined on any Iterable, and it returns an
Iterator; so after x = y.__iter__() (or x = iter(y) of course) you
know that x is an Iterator, even if you know nothing about y's type
(though if y is not an Iterable, the expresion may raise an
exception).

OTOH if you see x = copy(y), you don't know anything about x unless
you know something about y; without knowing anything about y, all you
know is that x is an object.

Here's another way to look at it, maybe it'll help. My hunch is that
whenever someone writes x = copy(y), they actually know more about the
type of y than just that it is an object! Because if they knew
*nothing* about it, they wouldn't know whether copying was (a)
pointless (as it is for immutable objects), (b) impossible (e.g. for
sockets), or (c) useful (e.g. for lists).

When thinking about these kind of things I often place myself in the
position of a static type checker that happens to know something about
the types of some variables and is trying to gather more information.
Seeing x=iter(y) can provide new information about y (it must be an
Iterable). Seeing x=copy(y) provides no new information about y, since
all (well, most) objects can be copied. OTOH seeing x=y.copy() *does*
provide new information about y; it must be a type that has a .copy()
method. Now seeing x=len(y) *does* provide new information about y
(since we know which types support .__len__()).

I realize I'm doing a lousy job of explaining me. Please trust me that
there's something here. I will eventually get to it (maybe not today).

> Or, were you saying that the actual problem is that we can't know
> in advance the signature of  type(self).__init__()?

No, the __copy__ GF takes care of that concern.

> > The
> > type of the more constrained (but still generic in the sense of PEP
> > 3124) copy operation on mutable sequences is better defined -- it
> > returns another mutable sequence, with the understanding that it
> > typically returns something of the same type as its input, though not
> > always -- e.g. if I subclass dict but don't override .copy(), the
> > inherited .copy() method returns a dict, not my subclass.
>
> The part I'm not following in this paragraph is how a d.copy()
> method is any different from the d.__copy__() method that
> is called by the copy() function.  Both share the same underlying
> implementation and both have the same effects when overridden.

The difference is that *every* object has a .__copy__() method (it is
inherited from object, at least conceptually), but not every object
has a .copy() method.

> If all we want a guaranteed dict, why not write dict(obj)?
> This already works with all the dict lookalikes because they
> define obj.keys() and obj.__getitem__().

Well, the whole point of this discussion that dict(obj) is what you
should write if you want a guaranteed dict, and obj.copy() is what you
should write if you want a guaranteed mutable mapping of the same type
as obj. Just like you write list(obj) if you want a list and obj[:] if
you want a sequence of the same type as obj.

-- 
--Guido van Rossum (home page: http://www.python.org/~guido/)


More information about the Python-3000 mailing list