python递归实例变量共享数据
我试图创建一个递归函数来创建一棵树。每个节点都有一个tic-tac-toe游戏的状态,每个节点的子节点是下一个可能的移动 我将电路板的状态传递给递归函数。对于每一个可能的移动,我都会创建一个状态副本,然后进行该移动。这个新状态被传递给递归函数python递归实例变量共享数据,python,recursion,tree,tic-tac-toe,Python,Recursion,Tree,Tic Tac Toe,我试图创建一个递归函数来创建一棵树。每个节点都有一个tic-tac-toe游戏的状态,每个节点的子节点是下一个可能的移动 我将电路板的状态传递给递归函数。对于每一个可能的移动,我都会创建一个状态副本,然后进行该移动。这个新状态被传递给递归函数 #XXX #O O = state [1,1,1,-1,0,-1,1,1,1] #XXX playerX = 1 playerO = -1 class node: children = [] #holds all the children
#XXX
#O O = state [1,1,1,-1,0,-1,1,1,1]
#XXX
playerX = 1
playerO = -1
class node:
children = [] #holds all the children
state = [] #holds the state of the board as a list of ints
def __init__(self,st):
self.state = st
def addChild(self,child):
self.children.append(child) #if only giving birth was this easy
#returns a node with all it's children filled in
#cState is the state for this node
#currentPlayer flips sign every function call
#stateSize is the size of the board
def makeTreeXO(cState,currentPlayer,stateSize):
newNode = node(cState)
for i in range(stateSize):
print "looking at", i, "in", cState
if(cState[i] == 0): #found an open space
print "found an empty space"
newState = cState #create copy of state
newState[i] = currentPlayer #make the available move
print "made new state"
newNode.addChild(makeTreeXO(newState,currentPlayer*-1,stateSize))
print "Done with this instance"
return newNode
root = makeTreeXO([1,0,0,1,1,1,1,1,1],playerX,9)
输出:
looking at 0 in [1, 0, 0, 1, 1, 1, 1, 1, 1]
looking at 1 in [1, 0, 0, 1, 1, 1, 1, 1, 1]
found an empty space
made new state
looking at 0 in [1, 1, 0, 1, 1, 1, 1, 1, 1]
looking at 1 in [1, 1, 0, 1, 1, 1, 1, 1, 1]
looking at 2 in [1, 1, 0, 1, 1, 1, 1, 1, 1]
found an empty space
made new state
looking at 0 in [1, 1, -1, 1, 1, 1, 1, 1, 1]
looking at 1 in [1, 1, -1, 1, 1, 1, 1, 1, 1]
looking at 2 in [1, 1, -1, 1, 1, 1, 1, 1, 1]
looking at 3 in [1, 1, -1, 1, 1, 1, 1, 1, 1]
looking at 4 in [1, 1, -1, 1, 1, 1, 1, 1, 1]
looking at 5 in [1, 1, -1, 1, 1, 1, 1, 1, 1]
looking at 6 in [1, 1, -1, 1, 1, 1, 1, 1, 1]
looking at 7 in [1, 1, -1, 1, 1, 1, 1, 1, 1]
looking at 8 in [1, 1, -1, 1, 1, 1, 1, 1, 1]
Done with this instance
looking at 3 in [1, 1, -1, 1, 1, 1, 1, 1, 1]
looking at 4 in [1, 1, -1, 1, 1, 1, 1, 1, 1]
looking at 5 in [1, 1, -1, 1, 1, 1, 1, 1, 1]
looking at 6 in [1, 1, -1, 1, 1, 1, 1, 1, 1]
looking at 7 in [1, 1, -1, 1, 1, 1, 1, 1, 1]
looking at 8 in [1, 1, -1, 1, 1, 1, 1, 1, 1]
Done with this instance
looking at 2 in [1, 1, -1, 1, 1, 1, 1, 1, 1]
looking at 3 in [1, 1, -1, 1, 1, 1, 1, 1, 1]
looking at 4 in [1, 1, -1, 1, 1, 1, 1, 1, 1]
looking at 5 in [1, 1, -1, 1, 1, 1, 1, 1, 1]
looking at 6 in [1, 1, -1, 1, 1, 1, 1, 1, 1]
looking at 7 in [1, 1, -1, 1, 1, 1, 1, 1, 1]
looking at 8 in [1, 1, -1, 1, 1, 1, 1, 1, 1]
Done with this instance
从print语句可以清楚地看出,对状态所做的更改将被带回函数的父实例。有人知道为什么吗?问题是,您正在修改类变量,它们将由特定类的所有对象共享。要解决此问题,请将
状态
和子项
设置为如下实例变量
class node:
def __init__(self,st):
self.state = st
self.children = []
def addChild(self,child):
self.children.append(child) #if only giving birth was this easy
newState = cState[:] #create copy of state
按照这条线,
newState = cState #create copy of state
您正在尝试创建cState
的副本并将其存储在newState
中。请记住,在Python中,赋值运算符从不将一个值复制到另一个值。它只是使左侧的变量指向赋值语句右侧表达式的求值结果
因此,您实际上要做的是使newState
和cState
指向同一个列表。因此,如果修改newState
,它也会影响cState
。要实际创建列表的副本,可以使用切片操作符,如下所示
class node:
def __init__(self,st):
self.state = st
self.children = []
def addChild(self,child):
self.children.append(child) #if only giving birth was this easy
newState = cState[:] #create copy of state
问题是,在修改类变量时,它们将由特定类的所有对象共享。要解决此问题,请将
状态
和子项
设置为如下实例变量
class node:
def __init__(self,st):
self.state = st
self.children = []
def addChild(self,child):
self.children.append(child) #if only giving birth was this easy
newState = cState[:] #create copy of state
按照这条线,
newState = cState #create copy of state
您正在尝试创建cState
的副本并将其存储在newState
中。请记住,在Python中,赋值运算符从不将一个值复制到另一个值。它只是使左侧的变量指向赋值语句右侧表达式的求值结果
因此,您实际上要做的是使newState
和cState
指向同一个列表。因此,如果修改newState
,它也会影响cState
。要实际创建列表的副本,可以使用切片操作符,如下所示
class node:
def __init__(self,st):
self.state = st
self.children = []
def addChild(self,child):
self.children.append(child) #if only giving birth was this easy
newState = cState[:] #create copy of state
一个问题是这一行:
newState = cState
从您的评论来看,您似乎试图复制cState,但是,您只是复制对列表的引用,而不是列表的内容。因此,当您修改newState时,您也在修改cState。你应该做的是:
newState = cState.copy()
编辑
因为这是公认的答案,所以完整的解决方案还包括在节点的构造函数中设置
self.children=[]
,正如@thefourtheye所提到的一个问题是这一行:
newState = cState
从您的评论来看,您似乎试图复制cState,但是,您只是复制对列表的引用,而不是列表的内容。因此,当您修改newState时,您也在修改cState。你应该做的是:
newState = cState.copy()
编辑
因为这是公认的答案,所以完整的解决方案还包括在节点的构造函数中设置
self.children=[]
,正如@thefourtheye所提到的,这不是唯一的问题,也是一个重要的问题。这两个问题和您发现的第四个类变量问题都是意外数据更改错误的来源。如果出现这种情况,具有更复杂数据结构的读者应该记住,copy()
是一种浅拷贝-对于某些结构来说,copy.deepcopy
是必需的。这不是唯一的问题,也是一个重要的问题。这两个问题和您发现的第四个类变量问题都是意外数据更改错误的来源。如果出现这种情况,具有更复杂数据结构的读者应该记住,copy()
是一种浅拷贝-对于某些结构,需要copy.deepcopy
。