Special method __copy__ is the easiest way for an object to cooperate with the copy.copy function, but how do you bypass the object's __init__, if it's slow, to get an 'empty' object of this class? Easy -- here's how.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
# a function makes the idiom available # non-invasively, everywhere: def empty_copy(object): class Empty: pass newcopy = Empty() newcopy.__class__ = object.__class__ return newcopy # now your class can easily use this function class YourClass: def __init__(self): print "assume there's a lot of work here" def __copy__(self): newcopy = empty_copy(self) print "now you can easily copy a relevant" print "subset of self's attributes to newcopy"
Python doesn't implicitly copy your objects when you assign them -- a great thing, too, fast and flexible and uniform semantics. When you need copies, you explicitly ask for them, ideally with function copy.copy, which knows how to copy built-in types, has reasonable defaults for your own objects, and also lets you customize the copying process by defining a special method __copy__.
The latter typically needs to start with an empty instance of the same class as self's -- bypassing __init__, when that is a costly operation. How? The simplest way is to use the ability that Python gives you to change an instance's class on the fly -- create a new object in a local empty class, then set its __class__ attribute, as the above code shows. (After that, you typically need to copy a subset of self's attributes -- if you need them all you're better off NOT defining __copy__, as that is copy.copy's default, unless you need to do a little bit more besides the copy; if you do need to get all of self's attributes, newcopy.__dict__.update(self.__dict__) can work, or you can use newcopy.__dict__=self.__dict__.copy()).
An alternative is to "import new" and use newcopy=new.instance(self.__class__, None) (or, new.instance(self.__class__, self.__dict__)). That's fine, too, if you're familiar and comfortable with module new -- however, module new is often thought of as dangerous black magic, and you can easily avoid using it for this purpose if you follow this recipe.