Reputation: 1098
I realize questions quite similar to this have been asked, though not exactly this way.
I'd like to have an optional argument for the constructor of my class that, if it is an instance of my class, will be copied. For example, something like (I know this code does not work!):
class Foo(object):
def __init__(self, foo=None):
self.x = None
self.y = None
self.z = None
if foo is not None and isinstance(foo, Foo):
self = copy.deepcopy(foo)
a = Foo()
a.x = 1
a.y = 2
a.z = 3
b = Foo(a)
print b.x
print b.y
print b.z
I know there are a few practical solutions to this. I could set each attribute of self according to the value of foo's corresponding attribute, but this would be really annoying because my class has many, many attributes. Or I could simply use do:
b = copy.deepcopy(a)
...But I'd rather not if that is possible. I'm also hoping to avoid overriding __new__
.
Is there really no decent way at all in python to create a copy constructor?
Upvotes: 16
Views: 19133
Reputation: 1602
One good way to do this is to make a top-level copy of instance's namespace.
class Tst:
def __init__(self, somearg):
if isinstance(somearg, self.__class__):
self.__dict__ = somearg.__dict__.copy()
else:
self.var = somearg
def echo(self):
print(self.var)
a = Tst(123)
b = Tst(456)
a.echo() # gives 123
b.echo() # gives 456
c = Tst(a)
c.echo() # gives 123
c.var is a.var # gives False -> different objects
But be careful if your class deals with __slots__
, because in that case __dict__
could be absent and thus you may need to rely on more neutral attribute-getting mechanisms, such as getattr()
Upvotes: 0
Reputation: 9161
It's possible, in that you can just iterate over all attributes on the source object passed to __init__
, and then setattr()
the ones you care about on self
. But it's not at all clear this would be a good way to solve a problem. Not very Pythonic, and all.
Upvotes: 0
Reputation: 54089
I think this is the most pythonic way of doing it - a copy factory method.
import copy
class Foo(object):
def __init__(self):
self.x = None
self.y = None
self.z = None
def copy(self):
return copy.deepcopy(self)
a = Foo()
a.x = 1
a.y = 2
a.z = 3
b = a.copy()
print b.x
print b.y
print b.z
This is fairly common in python basic types (eg dict.copy
). It is not a copy constructor, but I don't think that is a very pythonic concept!
Upvotes: 24