python - 在Python中对对象应用函数

标签 python class artificial-life

我写了一个人工生命模拟。每个生物都是我定义的“动物”类的对象,具有一些属性。我在 Animal 类之外定义了一个函数“regenerate”:

def reproduce(parent):
    child = Animal()
    child.brain.w= parent.brain.w[:]
    child.brain.ix= parent.brain.ix[:]
    child.x,child.y = random.randint(0,width),random.randint(0,height)
    child.age = 0
    child.fitness= 9 + parent.fitness/10 #parent.fitness/2

    mutation = random.choice([0,1,1,1,1,1,1,1,1,2,3,4,5])
    for b in range(mutation):
      child.brain.mutate()
    animals.append(child)

可以看出,每只动物都有一个大脑,它是来自不同类的对象:对于每只动物,我定义了 animals[i].brain = Brain()。复制函数中的“变异”部分确保 child 的大脑与 parent 的大脑不同。

然而,问题是,当我将此功能应用于列表中的某些动物时, child 确实获得了稍微新的大脑,但 parent 的大脑变得与 child 的新大脑相同。当我使用 reproduct(copy.deepcopy(animals[i])) 而不是 reproduct(animals[i]) 时,不会发生这种情况。原因是什么?

谢谢!

最佳答案

基于@Armin 评论的另一次尝试。这确实表现出相关的深度复制行为:

import random

width = 5
height = 5

class Brain(object):

    def __init__(self):
        self.w = [[1]]
        self.ix = [[1]]

    def mutate(self):
        self.w[0].append(1)

class Animal(object):

    def __init__(self):
        self.brain = Brain()
        self.x = random.randint(0, width)
        self.y = random.randint(0, height)
        self.age = 0
        self.fitness = 10

def reproduce(parent):
    child = Animal()
    child.brain.w= parent.brain.w[:]
    child.brain.ix= parent.brain.ix[:]
    child.x,child.y = random.randint(0,width),random.randint(0,height)
    child.age = 0
    child.fitness= 9 + parent.fitness/10 #parent.fitness/2

    mutation = random.choice([0,1,1,1,1,1,1,1,1,2,3,4,5])
    for b in range(mutation):
      child.brain.mutate()
    animals.append(child)

animals = []
parent = Animal()

animals.append(parent)
print parent.brain.w
#reproduce(parent)
import copy
reproduce(copy.deepcopy(parent))

for each in animals:
    print each.brain.w

此处的解决方法是不要将状态值存储在您在对象之间复制的可变类型中;在本例中是一个列表,但它可以是任何可变对象。

编辑: 您在原始代码中所做的是将 parent.brain.w 的内容复制到 child.brain.w 中。 Python 具有这样的属性:赋值是针对原始对象,而不是对象或内容的副本(除非您使用 copy 模块)。 The docs盖好这个。简而言之,这意味着以下内容是正确的:

>>> a = [1, 2, 3, 4, 5]
>>> b = a
>>> b.append(6)
>>> b
[1, 2, 3, 4, 5, 6]
>>> a
[1, 2, 3, 4, 5, 6]
>>> a is b
True

也就是说,ab 都是同一个列表。那不完全是你正在做的事情;您将列表复制到对象中,但这是等效的:

>>> a = [[1, 2, 3]]
>>> b = []
>>> b = a[:] # What you are doing
>>> b is a
False
>>> b[0] is a[0]
True
>>> b[0].append(4)
>>> b[0]
[1, 2, 3, 4]
>>> a[0]
[1, 2, 3, 4]

如果您的类型不可变,那么当您修改它时,就会创建一个新对象。例如,考虑一个稍微等效的元组列表(它们是不可变的):

>>> a = [(1, 2, 3)]
>>> b = []
>>> b = a[:]
>>> b is a
False
>>> b[0] is a[0] # Initially the objects are the same
True
>>> b[0] += (4,) # Now a new object is created and overwrites b[0]
>>> b[0] is a[0]
False
>>> b[0]
(1, 2, 3, 4)
>>> a[0]
(1, 2, 3)

关于python - 在Python中对对象应用函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15180125/

相关文章:

c++ - 在一个命令中使用 2 个重载运算符会导致错误

css - 在 CSS 中更改类的背景颜色不起作用?

open-source - 多用途3D人工生命引擎?

python - Pandas :将新列添加到数据框,这是索引列的副本

类似于 Python 的 Java 类列表

python - 在 url.py 中包含关键字在没有 app_name 的情况下不起作用(Django 2.0)

python - 蚁群模拟——优化路径

python - Django 模板中的字典 - 过滤器使用

java - Java中无法调用另一个类的方法

java - 植绒小鸟行为问题