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.
new.instance does this already. The module "new" already contains this.
hmmmm... Sorry, I should have read till the end, and you cannot remove comments... :/
new.instance ? Shouldn't it rather be : new.instance(self.__class__, self.__dict__.copy() )