14

I have two classes. They're almost identical, except for 2 attributes. I need to copy all the attributes over from one to the other, and I'm just wondering if there is a pattern or best practice, or if I should just basically do:

spam.attribute_one = foo.attribute_one
spam.attribute_two = foo.attribute_two

... and so on.

orokusaki
  • 55,146
  • 59
  • 179
  • 257
  • 3
    why don't you use inheritance ? – shahjapan Sep 29 '10 at 05:09
  • @Tumbleweed - They're ORM classes. One is for transaction record keeping in the database, and they have such different uses, methods, etc that it's just more work in the long run to try to use inheritance (not to mention I plan to clean out the one, and keep the other permanently). – orokusaki Sep 29 '10 at 05:20

3 Answers3

20

The code you give is correct and safe, avoiding "accidentally" binding attributes that should not be bound. If you favor automation over safety and correctness, though, you could use something like...:

def blindcopy(objfrom, objto):
    for n, v in inspect.getmembers(objfrom):
        setattr(objto, n, v);

However, I would not recommend it (for the reasons implied by the first para;-). OTOH, if you know the names of the attributes you want to copy, the following is just fine:

def copysome(objfrom, objto, names):
    for n in names:
        if hasattr(objfrom, n):
            v = getattr(objfrom, n)
            setattr(objto, n, v);

If you do this kind of thing often, having this code once in a "utilities" module can be a definite win for you!

galarant
  • 1,959
  • 19
  • 24
Alex Martelli
  • 854,459
  • 170
  • 1,222
  • 1,395
  • thanks yet again. I kind of like your second method, but I'll stick with your advice and do it the correct and safe way. Having a tuple of field names won't spare me much code-space/cleanliness anyways. – orokusaki Sep 29 '10 at 05:18
  • 2
    the for-loop in the blindcopy-function misses the in-operator. – Geoffrey Oct 21 '10 at 20:07
3

If they're that similar, and need to change state, it sounds like you really have instances of one class, and a mode or similar attribute that determines how it behaves. Objects shouldn't morph from one object to another, similar but separate object, very often at all.

Peter
  • 127,331
  • 53
  • 180
  • 211
  • Sort of, but their use is different enough to warrant two classes. Also, their ORM classes, and one is for record keeping. The other will be purged periodically. – orokusaki Sep 29 '10 at 05:14
0

I used dictionary comprehension to iterate through the items and call setattr() for another object.

{k: setattr(object_to, k, v) for k, v in object_from.dict().items()}

Since I don't need any new dict, I have not assigned the return value to any variable.

Another way I tried is by using map()

dict(
    map(lambda item: (item[0], setattr(object_to, item[0], item[1])
                      ),
        object_from.dict().items()
        )
)

This might save a lot of loop iteration time.

Neisha
  • 11
  • 2