【问题标题】:Constant Variable is being changed常量变量正在改变
【发布时间】:2013-07-23 19:45:58
【问题描述】:

我正在重新制作我的战舰游戏,我有一个名为 SEA 的常量变量,它包含一个空棋盘。但是,变量正在被修改,我不知道为什么(或在哪里)。我怀疑它是通过引用 player_board 传递的,当 player_board 被修改时,SEA 也是如此。我该如何阻止这种情况发生?这是我的代码。你会在底部看到我打印出 SEA,它已经被修改了。

from random import randint
#Constants and globals
OCEAN = "O"
FIRE = "X"
HIT = "*"
SIZE = 10
SHIPS = [5, 4, 3, 3, 2]
player_radar = []
player_board = []
player_ships = []
ai_radar = []
ai_board = []
ai_ships = []

#Classes
class Ship(object):
    def set_board(self, b):
        self.ship_board = b
    def edit(self, row, col, x):
        self.ship_board[row][col] = x
    def __repre__(self):
        return self.ship_board

#Set up variables
last_ship = Ship() #Holds the last ship made in make_ship()
SEA = [] # Blank Board
for x in range(SIZE):
    SEA.append([OCEAN] * SIZE)

#Functions
def print_board():
    for row in range(SIZE):
        print " ".join(player_radar[row]), "||" , " ".join(player_board[row])

def random_row(is_vertical, size):
    if is_vertical:
        return randint(0, SIZE - size)
    else:
        return randint(0, SIZE -1)

def random_col(is_vertical, size):
    if is_vertical:
        return randint(0, SIZE - 1)
    else:
        return randint(size-1, SIZE -1)

def exists(row, col, b): # true if ocean
    if row < 0 or row >= SIZE:
        return 0
    elif col < 0 or col >= SIZE:
        return 0
    if b[row][col] == OCEAN:
        return 1
    else:
        return 0

def make_ship(size, board):
    #Find an unoccupied spot, then place ship on board
    #Also put ship in last_ship
    temp = []
    temp = board
    is_vertical = randint(0, 1) # vertical ship if true
    occupied = True
    while(occupied):
        occupied = False
        ship_row = random_row(is_vertical, size)
        ship_col = random_col(is_vertical, size)
        if is_vertical:
            for p in range(size):
                if not exists(ship_row+p, ship_col, temp):
                    occupied = True
        else:
            for p in range(size):
                if not exists(ship_row, ship_col-p, temp):
                    occupied = True
    #Place ship on boards
    last_ship.set_board(SEA)
    if is_vertical:
        last_ship.edit(ship_row, ship_col, "^")
        last_ship.edit(ship_row+size-1, ship_col, "v")
        temp[ship_row][ship_col] = "^"
        temp[ship_row+size-1][ship_col] = "v"
        for p in range(size -2):
            last_ship.edit(ship_row+p+1, ship_col, "+")
            temp[ship_row+p+1][ship_col] = "+"
    else:
        last_ship.edit(ship_row, ship_col, ">")
        last_ship.edit(ship_row, ship_col-size+1, "<")
        temp[ship_row][ship_col] = ">"
        temp[ship_row][ship_col-size+1] = "<"
        for p in range(size -2):
            last_ship.edit(ship_row, ship_col-p-1, "+")
            temp[ship_row][ship_col-p-1] = "+"
    return temp

# Make the boards
player_radar = SEA
player_board = SEA
ai_radar = SEA
ai_board = SEA
print_board()
for x in SHIPS:
    player_board = make_ship(x, player_board)
    #player_ships.append(last_ship)
    #ai_board = make_ship(x, ai_board)
    #ai_ships.append(last_ship)

print "Let's play Battleship!"
for row in range(SIZE):
    print " ".join(SEA[row])

【问题讨论】:

标签: python


【解决方案1】:

SEA 及其成员是列表,Python 中的列表是可变的。当你说player_radar = SEA等时,你不是在复制SEA;您正在对它进行新的引用。您随后对player_radar 所做的任何更改都将反映在SEA 中。

copy.deepcopy 通常用于递归复制嵌套的可变数据结构。然而,就我个人而言,我更喜欢只复制我知道我需要的层数。例如,要复制列表及其所有成员的列表,您可以这样做:

player_radar = [sublist[:] for sublist in SEA]

这是list comprehension。每个子列表都使用[:] 进行复制,这会对每个子列表进行浅拷贝。

【讨论】:

  • 如果您想要一份列表等的副本,请使用copy.deepcopy 确保您确实复制了所有级别。
  • @9000:不一定。如果您将列表列表视为二维列表,您通常希望复制子列表,而不是子列表的元素。
  • 重要提示:当您说x=y 时,无论y 的类型如何,您永远不会“复制”。如果 SEAintstr,那么您仍然会创建新的引用,而不是副本。
  • @user2357112 我还是更喜欢使用copy 库来获得更清晰的语义。您的观点仍然有效且正确:)
【解决方案2】:

SEA 是一个列表,因此请复制一份:

player_radar = SEA[:]
player_board = SEA[:]
ai_radar = SEA[:]
ai_board = SEA[:]

如果需要的话,可以更深入地复制它。

编辑:通过“更深的副本”,我的意思是,如果您的列表包含例如其他列表,那么仅制作顶级副本将创建一个新列表,但其成员将引用您的相同成员原始列表有,因此要创建深层副本,您还需要复制这些成员。

举例说明:

>>> list1 = [[1,2,3]]
>>> list2 = list1[:]    # Make a shallow copy
>>> print(list1)
[[1,2,3]]
>>> print(list2)
[[1,2,3]]
>>> list2[0][0] = 4     # Also changing list1's first member, here
>>> print(list2)
[[4,2,3]]
>>> print(list1)
[[4,2,3]]               # So list1 has also changed.

【讨论】:

【解决方案3】:

Python 变量是事物的名称,而不是放置事物的地方。

player_radar = SEA

不会像在 C++ 中那样使 player_radar 成为 SEA 的副本。相反,player_radarSEA 都是同一个列表对象的名称。如果您更改 player_radar,您将看到 SEA 以及引用同一对象的所有其他变量的更改。

【讨论】:

  • 在 C++ 中,player_radarSEA 都只是指针。
  • @9000:仅当您将它们声明为指针并newed 他们而不是使用类似 vector&lt;vector&lt;Ship&gt;&gt; 的东西时。
  • 此外,每当您为带有指针成员变量的 C++ 类编写复制构造函数或赋值运算符时,您都需要处理非常相似的问题,即您是否只想复制指针(通常不是,但有时你会这样做)或者你想要复制它所指向的东西,然后指向它。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-02-04
相关资源
最近更新 更多