python - 是否可以从一个列表中复制一个项目并多次放入另一个列表中,然后单独修改每个项目?
问题描述
我正在开发一个与《炉石传说》的战场模式类似概念的纸牌游戏项目(用于练习和娱乐)。我试图将两张或多张同一张牌放在玩家手中,然后单独修改其值。目前,当一张卡应该被修改时,它会同时改变。
首先,我引入怪物 json 并将其深度复制到一个列表中,以便我可以 1)修改条目和 2)保留原始值的引用:
gameDeck = []
with open('monsters.json', 'r') as f:
monsters = json.load(f)
gameDeck = copy.deepcopy(monsters)
怪物条目的示例(它是列表中的字典):
[
{ "name": "Jerry",
"hp": 1,
"str": 1,
"type": "human",
"amount": 10,
"ability": "",
"ability-property":"",
"ability-property-amount":""
},
然后我将卡片添加到用户手中(强制,用于测试):
def forceAssignUser(user, gameDeck):
user.addCard(card, gameDeck)
user.addCard(card, gameDeck)
.addCard 看起来像:
class Player:
#...
# adds a card to the players hand, removes the card from the deck
def addCard(self, card, gameDeck):
self.hand.append(card)
# gameDeck.remove(card)
card['amount'] -= 1
当然,现在在奔跑和“战斗”阶段,当一张牌受到伤害时,它也会被复制。我试过了,但结果是一样的:
def forceAssignUser(user, gameDeck):
card = copy.deepcopy(gameDeck[0])
user.addCard(card, gameDeck)
user.addCard(card, gameDeck)
这是“战斗”阶段的一部分,大部分变化都发生在这里(不漂亮,我知道):
while userAlive is not False and opponentAlive is not False:
if whoseTurn == "u":
if userMonAtk >= len(user.hand):
#what monster will attack
userMonAtk = 0
while checkCardHealth(user, userMonAtk) <= 0:
#use next monster if current is dead
userMonAtk += 1
#choose a random target
randOpponentMon = random.randint(0, len(user.hand) - 1)
while opponent.hand[randOpponentMon]['hp'] <= 0:
#reroll if chosen enemy dead
randOpponentMon = random.randint(0, len(user.hand) - 1)
usMonster = user.hand[userMonAtk] #store the card info
opMonster = opponent.hand[randOpponentMon]
opMonster['hp'] -= usMonster['str'] #when attacking or being attacked, take damage
usMonster['hp'] -= opMonster['str']
printBoard(user, opponent)
print("Your {0} attacks opponent's {1}!".format(usMonster['name'], opMonster['name']))
opponentAlive = checkDeckHealth(opponent)
userAlive = checkDeckHealth(user)
input("Press anything to continue.")
whoseTurn = "o"
userMonAtk += 1
甚至有可能做我想做的事吗?我不擅长编码,所以我的很多代码都围绕着逻辑、方法和类。
解决方案
假设你有几个对象(Python 的object
内置是有用的替代品,因为它 repr 包括它的地址):
>>> o1,o2=object(), object()
>>> o1
<object object at 0x10817e430>
>>> o2
<object object at 0x10817e450>
现在列出这些对象:
>>> li=[o1,o2]
>>> li
[<object object at 0x10817e430>, <object object at 0x10817e450>]
一个典型的副本会使用一个切片来做一个浅拷贝:
>>> li_copy=li[:]
>>> li_copy
[<object object at 0x10817e430>, <object object at 0x10817e450>]
这意味着li
和li_copy
是两个不同的列表;您可以修改一个而不修改另一个:
>>> li_copy[0]='not an object() anymore'
>>> li
[<object object at 0x10817e430>, <object object at 0x10817e450>]
>>> li_copy
['not an object() anymore', <object object at 0x10817e450>]
尽管它们是两个独立的列表,但它们确实包含相同的对象;如果你修改<object object at 0x10817e430>
它也会改变li
。
但是如果你使用deepcopy
你会得到两个带有两个独立对象的单独列表:
>>> import copy
>>> li_3=copy.deepcopy(li)
>>> li_3
[<object object at 0x10817e4b0>, <object object at 0x10817e4c0>]
# note that the addresses have changed - these are new objects that could
# be modified without changing the object in the other list.
并非所有对象都支持深度复制;有时 deepcopy 函数会简单地做与切片复制相同的事情。
Deepcopy 需要通过定义__deepcopy__()
它必须支持创建具有第一个实例的默认值但又是一个新实例的新对象的功能来定义。它object()
只是一个哑对象,它只是object()
再次调用。
因此,在您的情况下执行此操作的方法是定义一个Card
对象并定义一个__deepcopy__
方法,该方法使用复制源的值创建一张新卡。
推荐阅读
- java - mongodb java过滤器问题与numberlong
- sql - 在 SEDE(Stack Exchange 数据资源管理器)中获取所有带有自我接受答案的帖子
- javascript - 如何在Vue JS中通过v-model检查输入框是否为空?
- html - JavaScript React Redux:数据库中的字段未在网页中呈现并且无法在下拉菜单中选择值
- bash - 如何在启用 FIPS 的 RedHat6 服务器上禁用 OpenSSL md5 散列
- pytorch - 如何在pytorch中增加批量大小
- flutter - Flutter,获取数据库记录,然后是互联网 json
- leaflet - 如何在不破坏“流”显示的情况下将弹出窗口或绑定弹出窗口添加到 Leaflet FlowMap 中的点/标记?
- php - Laravel 删除数组中具有重复值的对象
- python - 熊猫数据框不断添加到现有的