deepcopy chokes with TypeError on dynamically assigned instance method

‘5ÛHH575-UAZWKVVP-7H2H48V3 kanenas at tcomcastd.tnet
Thu Feb 10 03:54:04 EST 2005


(see end of message for example code)

When an instance has a dynamically assigned instance method, deepcopy
throws a TypeError with the message "TypeError: instancemethod
expected at least 2 arguments, got 0".  Tested with Python 2.3.4 on
OpenBSD and Python 2.4 on Win98; same results.  Is this a bug in
deepcopy, how I dynamically assign the instance method or something
else?  (See example code for how I did it.)

If you're curious as to why the deep copy and dynamic assign are
necessary or have implementation suggestions (or alternatives), I bet
you'd like some details.  The TypeError cropped up while coding a
'Point' class representing cartesian coordinates.  I needed to
overload an 'origin' method as both a class method and an instance
method (if Python were more Perlesque... ;-) ).  'origin' returns a
point representing an origin.  The class method requires an argument
for the dimension of the origin, while the instance method uses the
dimension of an instance (ortus overloading).  As the instance
reference isn't bound when the class 'origin' method is defined,
there's no way to use a default argument.  I instead dynamically
assign an instance method to the 'origin' attribute of the instance.

As for the deepcopy, scalars aren't necessarily of a built-in numeric
type, though I generally expect them to be numeric (you could use
lists or strings as scalars, but not many methods would still be
usable).  Point is the base clase for Vector, and I want (e.g.)
vectors of vectors so I can eventually extend Vector to Matrix and
Tensor.  The Point constructor has a single argument: a sequence of
scalars (which, as noted, can be sequences).  In practice, the
sequence itself will be a tuple, a list, a Point or descendant of
Point (so that Point can act as a copy constructor).  To prevent a
copied point from aliasing elements of a different Point, I used
deepcopy.  When the TypeError struck, I switched to a generator, which
works as long as every constructor functions as a copy constructor
(not necessarily true, apparently, of lists, but true of Points).  I
could also implement copy-on-write semantics for coordinates or
implement __deepcopy__ for Point (which will probably be the final
solution).


example code:

from copy import copy,deepcopy
import new

class Foo(list):
    "Foo"

    def __init__(self, l=[]):
	list.__init__(self, deepcopy(l))
	# using generator rather than deepcopy produces no errors. 
	#list.__init__(self, [copy(el) for el in l])
	# 'copy(el)' in generator results in a deepcopy of sequence
	# as long as each object encountered uses a copy constructor
	# (which I expect of numeric types) and doesn't implement 
	# a shallow __copy__.  Alternative is to use type(el)(el):
	#list.__init__(self, [type(el)(el) for el in l])
	def bar(self):
	    return 'bar'
	self.bar=new.instancemethod(bar, self, self.__class__)
	# also causes deepcopy to choke:
	#self.bar = self._bar

    def _bar(self):
	return 'bar'

    #deepcopy has no problem with this
    bar = _bar
	
    def __repr__(self):
	return self.__class__.__name__+'(['\
		+','.join(map(str, self))+'])'

# causes deepcopy to throw a TypeError
Foo(Foo('foo'))




More information about the Python-list mailing list