[Python-Dev] copy confusion

Alex Martelli aleax at aleax.it
Tue Jan 11 23:50:55 CET 2005


On 2005 Jan 11, at 23:20, Fredrik Lundh wrote:

> back in Python 2.1 (and before), an object could define how copy.copy 
> should
> work simply by definining a __copy__ method.  here's the relevant 
> portion:
>
>     ...
>     try:
>         copierfunction = _copy_dispatch[type(x)]
>     except KeyError:
>         try:
>             copier = x.__copy__
>         except AttributeError:
>             raise error, \
>                   "un(shallow)copyable object of type %s" % type(x)
>         y = copier()
>     ...
>
> I recently discovered that this feature has disappeared in 2.3 and 
> 2.4.  in-
> stead of looking for an instance method, the code now looks at the 
> object's
> type:

Hmmm, yes, we were discussing this general issue as part of the huge 
recent thread about pep 246.  In the new-style object model, special 
methods are supposed to be looked up on the type, not on the object; 
otherwise, having a class with special methods would be a problem -- 
are the methods meant to apply to the class object itself, or to its 
instances?

However, apparently, the code you quote is doing it wrong:

>     cls = type(x)
>
>     copier = _copy_dispatch.get(cls)
>     if copier:
>         return copier(x)
>
>     copier = getattr(cls, "__copy__", None)
>     if copier:
>         return copier(x)

...because getattr is apparently the wrong way to go about it (e.g., it 
could get the '__copy__' from type(cls), which would be mistaken).  
Please see Armin Rigo's only recent post to Python-Dev for the way it 
should apparently be done instead -- assuming Armin is right (he 
generally is), there should be plenty of bugs in copy.py (ones that 
emerge when you're using custom metaclasses &c -- are you doing that?).

Still, if you're using an instance of an old-style class, the lookup in 
_copy_dispatch should be on types.InstanceType -- is that what you're 
trying to copy, an instance of an old-style class?


> (copy.deepcopy still seems to be able to use __deepcopy__ hooks, 
> though)

It starts with a peek into a dispatch dictionary for the type of the 
object, too, just like shallow copy does.  What's the type of what 
you're trying to copy?


> is this a bug, or a feature of the revised copy/pickle design?   (the 
> code in
> copy_reg/copy/pickle might be among the more convoluted pieces of 
> python
> coding that I ever seen...  and what's that smiley doing in copy.py?)
>
> and if it's a bug, does the fact that nobody reported this for 2.3 
> indicate that
> I'm the only one using this feature?  is there a better way to control 
> copying
> that I should use instead?

When I can, I use __getstate__ and __setstate__, simply because they 
seem clear and flexible to be (usable for copying, deep copying, 
pickling).  But that doesn't mean __copy__ or __deepcopy__ should be 
left broken, of course.

Although there are features of design intent here, it does appear to me 
there may be bugs too (if the getattr on the type is wrong); in this 
case it's worrisome, not just that nobody else reported problems, but 
also that the unit tests didn't catch them...:-(


Alex



More information about the Python-Dev mailing list