[Python-Dev] copy confusion

Alex Martelli aleax at aleax.it
Wed Jan 12 00:09:17 CET 2005


On 2005 Jan 11, at 23:58, Guido van Rossum wrote:
    ...
>>>     cls = type(x)
>>>     copier = _copy_dispatch.get(cls)
>>>     if copier:
>>>         return copier(x)
    ...
>>> is this a bug, or a feature of the revised copy/pickle design?
>
> [Phillip]
>> Looks like a bug to me; it breaks the behavior of classic classes, 
>> since
>> type(classicInstance) returns InstanceType.
>
> I'm not so sure. I can't seem to break this for classic classes.

You can't, _copy_dispatch deals with those.

> The only thing this intends to break, and then only for new-style
> classes, is the ability to have __copy__ be an instance variable
> (whose value should be a callable without arguments) -- it must be a
> method on the class. This is the same thing that I've done for all
> built-in operations (__add__, __getitem__ etc.).

And a wonderful idea it is.

>> However, it also looks like it might have been introduced to fix the
>> possibility that calling '__copy__' on a new-style class with a custom
>> metaclass would result in ending up with an unbound method.  (Similar 
>> to
>> the "metaconfusion" issue being recently discussed for PEP 246.)
>
> Sorry, my head just exploded. :-(
>
> I think I did this change (for all slots) to make the operations more
> efficient by avoiding dict lookups. It does have the desirable
> property of not confusing a class's attributes with its metaclass's
> attributes, but only as long as you use the operation's native syntax
> (e.g. x[y]) rather than the nominally "equivalent" method call (e.g.
> x.__getitem__(y)).

Unfortunately, we do have a problem with the code in copy.py:

class MetaCopyableClass(type):
     def __copy__(cls):
         """ code to copy CLASSES of this metaclass """
     # etc, etc, snipped

class CopyableClass:
     __metaclass__ = MetaCopyableClass
     # rest of class snipped

x = CopyableClass()

import copy
y = copy.copy(x)


kallisti:/tmp alex$ python x.py
Traceback (most recent call last):
   File "x.py", line 14, in ?
     y = copy.copy(x)
   File "/usr/local/lib/python2.4/copy.py", line 79, in copy
     return copier(x)
TypeError: __copy__() takes exactly 1 argument (2 given)
kallisti:/tmp alex$

See?  copy.copy(x) ends up using MetaCopyableClass.__copy__ -- because 
of a getattr on CopyableClass for '__copy__', which gets the 
BOUND-METHOD defined in the metaclass, with im_self being 
CopyableClass.

I had exactly the same metabug in the pep 246 reference implementation, 
Armin Rigo showed how to fix it in his only recent post.


Alex




More information about the Python-Dev mailing list