mooder
mooder

Reputation: 363

delete instance after addition

I'm trying to learn OOP with python. I'm wondering how I can create armies and when I merge them, delete the one that merged with the one specified.

class Army:
    def __init__(self, spear, sword, archer):
        self.composition = {'spear': spear, 'sword': sword, 'archer': archer}

    def __add__(self, other):
        for item in other.composition:
            self.composition[item] += other.composition[item]
        del other

Then typing this in the console:

army1 = Army(10, 20, 30)
army2 = Army(30, 5, 0)
army1+army2

doesn't delete army2. However, if I type del army2, it does delete the instance...

Upvotes: 3

Views: 63

Answers (3)

ShadowRanger
ShadowRanger

Reputation: 155418

The reason this doesn't work is that del on a raw name only unbinds the object from that specific name. If the object is referenced elsewhere, in this case by army2 in the caller, then the object continues to exist; del has no effect beyond denying access under the specific name del-ed.

If you must have this behavior, I recommend two things:

  1. Don't overload an operator for this behavior; + is not expected to affect either operand, it's supposed to produce a brand new object with the sum/concatenation of both. While += is allowed to modify the left hand operand, it shouldn't be modifying the right hand operand. When overloading operators, the usual rule of thumb is "Don't", followed by "Okay, but only if it obeys the expected semantics of that operator", and this case definitely doesn't match the expected semantics of either + or +=.
  2. Now that we've settled on using a method, you can remove the troops from the other army, by removing the contents of the other army. For example:

    class Army:
        def __init__(self, spear, sword, archer):
            self.composition = {'spear': spear, 'sword': sword, 'archer': archer}
    
        def absorb_army(self, other):  # or transfer_troops or whatever
            '''Removes all the troops from other, combining them with the troops of self'''
            for item in other.composition:
                self.composition[item] += other.composition[item]
            other.composition.clear()  # Leaves other.composition empty
    
    army1 = Army(10, 20, 30)
    army2 = Army(30, 5, 0)
    army1.absorb_army(army2)
    # army2 still exists, but all the troops in it are gone, moved to army1
    

Note that the absorb_army I wrote might violate other constraints of your class (because all elements of your class may be expected to have composition include 'spear', 'sword' and 'archer'. If that's an issue, don't clear it, just reassign all the keys to zero, e.g.:

        def absorb_army(self, other):
            for item in other.composition:
                self.composition[item] += other.composition[item]
                other.composition[item] = 0  # Zero after adding to self

Upvotes: 3

vasia
vasia

Reputation: 1172

The del keyword deletes a reference (or a name), not the object itself. Since you are using del from inside a function, you are deleting that reference only within the function. That's why you're still able to access army2 even after you add army1+army2.

Python has garbage collection built-in, so I wouldn't worry about manually deleting variables, you'll most likely actually just end up slowing things down.

Upvotes: 1

Thierry Lathuille
Thierry Lathuille

Reputation: 24231

del other will only make the 'other' name stop to exist and refer to your second army. That's all: just this name disappears, as it would have disappeared anyway once you exit this method.

The army2 object will only cease to exist once all the names referencing it will have been deleted and it gets garbage collected. That's not something you could do in your method.

Just let this second army get forgotten...

Upvotes: 1

Related Questions