简体   繁体   中英

These two codes should do exactly the same thing, but the first one doesn't work as I expect

Python

Please explain why these two codes work differently.. Actually I am trying to make kind of AI where in initial generations the individuals will go in random directions. For keeping the code simple I have provided some random directions in Brain myself.

There is an Individual class that gives a brain to the individual. It also has a function that returns a child with EXACTLY the same brain (means same directions to go in) as the parent.

I have two codes:

First: When some directions is changed in the parent, the same thing is changed in the child too (or if changed in child, it gets changed in parent too) which I don't want to happen.

Second: This one is not completely mine (and that's why I don't really know why it works) but it works fine. Some direction changed in parent is not changed in the child and vice-versa.

Please someone explain me the difference and why first one didn't work. I would really appreciate your answer.


First one:

class Brain():
    def __init__(self):
        self.directions = [[1, 2], [5, 3], [7, 4], [1, 5]]

class Individual():
    def __init__(self):
        self.brain = Brain()

    def getChild(self):
        child = Individual()
        child.brain = self.brain
        return child

parent = Individual()
child = parent.getChild()

parent.brain.directions[0] = [5, 2]

print(parent.brain.directions)
print(child.brain.directions)

[ [5, 2], [5, 3], [7, 4], [1, 5] ]

[ [5, 2], [5, 3], [7, 4], [1, 5] ]



Second one:

class Brain():
    def __init__(self):
        self.directions = [[1, 2], [5, 3], [7, 4], [1, 5]]

    def clone(self):
        clone = Brain()
        for i, j in enumerate(self.directions):
            clone.directions[i] = j
        return clone

class Individual():
    def __init__(self):
        self.brain = Brain()

    def getChild(self):
        child = Individual()
        child.brain = self.brain.clone()
        return child

parent = Individual()
child = parent.getChild()

parent.brain.directions[0] = [5, 2]

print(parent.brain.directions)
print(child.brain.directions)

[ [5, 2], [5, 3], [7, 4], [1, 5] ]

[ [1, 2], [5, 3], [7, 4], [1, 5] ]

In the first code, setting child.brain = self.brain doesn't do what you're expecting. That is a shallow copy, meaning that it just creates a new pointer to the same instance of Brain() . So now child.brain and self.brain both point to the same Brain() in memory.

In the second code, you are making a deep copy. Thus, you are actually allocating another Brain() in memory. Now child.brain and parent.brain point to their own separate instance of a Brain() in memory.

In first case you are referring same object. Try adding following print statement in first case.

print (id(parent.brain))
print (id(child.brain))

Have new reference for Brain() in first case. you can see how it handles.

class Brain():
    def __init__(self):
        self.directions = [[1, 2], [5, 3], [7, 4], [1, 5]]

class Individual():
    def __init__(self):
        self.brain = Brain()

    def getChild(self):
        child = Individual()
        child.brain = Brain()
        return child

parent = Individual()
child = parent.getChild()

parent.brain.directions[0] = [5, 2]

print(parent.brain.directions)
print(child.brain.directions)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM