gpt4 book ai didi

python - 无法在Python中使用外部函数更改类变量

转载 作者:行者123 更新时间:2023-11-30 22:07:56 25 4
gpt4 key购买 nike

因此,我制作了一个游戏,并试图为玩家创建一个清单,并且我无法更改名为“ equipped_weapon”的变量。我已经尝试了所有方法,或者得到了异常,或者在打印玩家的清单时显示了先前的武器。我也是初学者,所以如果我想念一些东西,请告诉我。

# Existing items
# Need a funtion to create a random item with random stats and a random name within a certain range.

yes_list = ["yes", "yeah", "sure", "why not"]

add_attack = "Attack:"
add_defense = "Defense:"
add_HP = "HP added:"
rarity = "Rarity"

weapon_rusty_sword = {
"Name:": "Rusty Sword",
add_attack: 1,
add_defense: 0,
rarity: 1
}

weapon_sword_wooden = {
"Name:": "Wooden Sword",
add_attack: 1.5,
add_defense: 0,
rarity: 1
}

weapon_sword_iron = {
"Name:": "Iron Sword",
add_attack: 2,
add_defense: 0,
rarity: 2
}

armor_chest_rusty_mail = {
"Name:": "Rusty Mail",
add_attack: 0,
add_defense: 1,
rarity: 1
}

armor_legs_adventurers = {
"Name:": "Adventurer's Leggings",
add_attack: 0,
add_defense: 1,
rarity: 1
}

armor_legs_rash_leggings = {
"Name:": "Rash Leggings",
add_attack: 0,
add_defense: 0.5,
rarity: 1
}

armor_head_rusty_cap = {
"Name:": "Rusty Cap",
add_attack: 0,
add_defense: 0.5,
rarity: 1
}
potion_hp = {
"Name:": "HP Potion,",
add_HP: 4
}

class Person:

#global equipped_weapon
equipped_weapon = weapon_rusty_sword
ui_equipped_weapon = {"Equipped Weapon: {}".format(weapon_rusty_sword): ""}

equipped_armor = {
"Head Protection:": {"Name": armor_head_rusty_cap["Name:"], "Defense": armor_head_rusty_cap[add_defense]},
"Chest Protection:": {"Name": armor_chest_rusty_mail["Name:"], "Defense": armor_chest_rusty_mail[add_defense]},
"Legs Protection:": {"Name": armor_legs_rash_leggings["Name:"], "Defense": armor_legs_rash_leggings[add_defense]},
}

ATTACK = 1 + equipped_weapon[add_attack]
DEFENSE = 1
HP = 20

gold = 10

potions = {"Potions: ": [potion_hp["Name:"]]}
ui_gold = {"Gold: ": gold}

def __init__(self):
self.name = "Cavalex"

inv = [
equipped_armor,
ui_equipped_weapon,
potions,
ui_gold
]

def see_inventory(self):
for element in self.inv:
for k, v in element.items():
if type(v) == list:
print(k, ' '.join(v))
else:
print(k, v)

# def equip_weapon(self, new_weapon_code):
# global equipped_weapon
# eq_val = input(
# "Do you want to equip this weapon? ->( {} )<-\nNote that your current weapon ( {} )will be discarded.".format(new_weapon_code["Name:"], self.equipped_weapon["Name:"]))
# if eq_val.lower() in yes_list:
# #del self.equipped_weapon
# self.equipped_weapon = new_weapon_code
# print("The weapon you had was discarded.")
# else:
# print("The new weapon was discarded.")





# See total amount of defense.
def defense_points():
return sum(value["Defense"] for key, value in player.equipped_armor.items())


def add_gold(amount):
player.gold += amount

# Adding to inventory
def new_potion_to_inv(potion):
player.potions["Potions: "].append(potion["Name:"])


def equipp_weapon(new_weapon_code):
# global player.equipped_weapon
eq_val = input(
"Do you want to equip this weapon? ->( {} )<-\nNote that your current weapon ( {} )will be discarded.".format(
new_weapon_code["Name:"], player.equipped_weapon["Name:"]))
if eq_val.lower() in yes_list:
del player.equipped_weapon
player.equipped_weapon = new_weapon_code
print("The weapon you had was discarded.")
else:
print("The new weapon was discarded.")

player = Person()

# game loop
while True:
print("Your name: ", player.name)
player.see_inventory() # Can't put print this function, else will print "None" in the end.
print("\nThis is your total armor defense: {}".format(defense_points()))
print()
new_potion_to_inv(potion_hp)
player.see_inventory()
print(player.ATTACK)
print()
print("Now we are changing your weapon.")
equipp_weapon(weapon_sword_iron)
print()
print(player.ATTACK)
player.see_inventory()



break


这是输出:

C:\Users\mateu\AppData\Local\Programs\Python\Python37-32\python.exe C:/Users/mateu/PycharmProjects/Trabalhos_Python/TESTING_THINGS/testing_armor_without_weapons_and_armor.py
Your name: Cavalex
Head Protection: {'Name': 'Rusty Cap', 'Defense': 0.5}
Chest Protection: {'Name': 'Rusty Mail', 'Defense': 1}
Legs Protection: {'Name': 'Rash Leggings', 'Defense': 0.5}
Equipped Weapon: {'Name:': 'Rusty Sword', 'Attack:': 1, 'Defense:': 0, 'Rarity': 1}
Potions: HP Potion,
Gold: 10

This is your total armor defense: 2.0

Head Protection: {'Name': 'Rusty Cap', 'Defense': 0.5}
Chest Protection: {'Name': 'Rusty Mail', 'Defense': 1}
Legs Protection: {'Name': 'Rash Leggings', 'Defense': 0.5}
Equipped Weapon: {'Name:': 'Rusty Sword', 'Attack:': 1, 'Defense:': 0, 'Rarity': 1}
Potions: HP Potion, HP Potion,
Gold: 10
2

Now we are changing your weapon.
Do you want to equip this weapon? ->( Iron Sword )<-
Note that your current weapon ( Rusty Sword )will be discarded.yes
Traceback (most recent call last):
File "C:/Users/mateu/PycharmProjects/Trabalhos_Python/TESTING_THINGS/testing_armor_without_weapons_and_armor.py", line 158, in <module>
equipp_weapon(weapon_sword_iron)
File "C:/Users/mateu/PycharmProjects/Trabalhos_Python/TESTING_THINGS/testing_armor_without_weapons_and_armor.py", line 139, in equipp_weapon
del player.equipped_weapon
AttributeError: equipped_weapon

Process finished with exit code 1

最佳答案

问题是您将equipped_weapon设置为类属性,而不是实例属性。 del instance.attribute仅删除实例属性,甚至不查找类属性。

如果目标只是更改实例,则可以完全删除del;否则,只需删除del。下一行将添加(如果不存在实例属性,则将class属性遮盖)或替换(如果已存在实例属性)实例的特定武器。

如果目标是更改班级,则需要更改分配以对班级进行操作:

type(player).equipped_weapon = new_weapon_code


或明确命名该类:

Player.equipped_weapon = new_weapon_code


无论哪种方式, del都是不必要的。分配新值将替换旧值,并以与 del type(player).equipped_weapon显式相同的方式隐式删除对旧值的引用。用 del Player.equipped_weapondel专门删除class属性是完全合法的,但这是没有意义的。无论所需的行为如何,简单地将其分配给class或instance属性都将丢弃旧的引用。

更新:如您所述,删除 see_inventory可以防止异常,但是您的输出(来自 see_inventory)永远不会改变。这是因为 Player.inv正在查看 Player.ui_equipped_weapon,而后者又包含对 ui_equipped_weapon原始值的引用。问题是,虽然 equipped_weaponequipped_weapon是基于相同的默认武器初始化的,但它们不会彼此同步。更改一个对另一个没有影响(因此,在类或实例上更改 inv不会影响 see_inventory,因此 property永远不会更改)。

确实,这里的解决方案是建立一个理智的课程。没有任何类属性有意义;从逻辑上讲,它们都是实例属性,应该这样定义。在某些情况下,它们只是另一个属性的面向便利的转换;在这些情况下,它们根本不应该是属性,而应该是 dict,它们会根据另一个属性动态地重新计算其值,从而防止它们不同步。

这是一个非常快速的重写(未经测试,可能有少量错别字),将所有合理的属性移到实例,并将其余的属性转换为只读属性,这些属性从另一个实例属性派生其值:

import copy

# Factored out to avoid repetition
def clean_armor(armor):
return {k.rstrip(':'): v
for k, v in armor.items() if k in {'Name:', 'Defense:'}}

class Person:
DEFAULT_WEAPON = weapon_rusty_sword
DEFAULT_ARMOR = {
"Head Protection:": clean_armor(armor_head_rusty_cap),
"Chest Protection:": clean_armor(armor_chest_rusty_mail),
"Legs Protection:": clean_armor(armor_legs_rash_leggings),
}

def __init__(self, name="Cavalex",
equipped_weapon=DEFAULT_WEAPON, equipped_armor=DEFAULT_ARMOR,
base_attack=1, base_defense=1,
hp=20, gold=10,
potions=(potion_hp["Name:"],)):
self.name = name
# deepcopy is defensive (so changing defaults doesn't retroactively
# alter existing instance); can be removed if you guarantee defaults
# won't be changed, or you want changes to defaults to affect
# Players still wielding default items
self.equipped_weapon = copy.deepcopy(equipped_weapon)
self.equipped_armor = copy.deepcopy(equipped_armor)
self.base_attack = int(base_attack)
self.base_defense = int(base_defense)
self.HP = int(hp)
self.gold = int(gold)
# potions only used as dictionary, but it's silly to store it as one
# Just store list of potion names in protected attribute,
# property can construct the expected dict on demand
self._potions = list(potions)

@property
def ATTACK(self):
return self.base_attack + self.equipped_weapon[add_attack]

@property
def DEFENSE(self):
return self.base_defense + sum(armor['Defense'] for armor in self.equipped_armor.values())

@property
def potions(self):
return {"Potions: ": self._potions}

@property
def ui_gold(self):
return {"Gold: ": self.gold}

@property
def ui_equipped_weapon(self):
return {"Equipped Weapon: {}".format(self.equipped_weapon): ""}

@property:
def inv(self):
return [
self.equipped_armor,
self.ui_equipped_weapon,
self.potions,
self.ui_gold,
]

def see_inventory(self):
for element in self.inv:
for k, v in element.items():
if isinstance(v, list):
print(k, ' '.join(v))
else:
print(k, v)


这仍然有很多可疑的选择(属性/属性命名不一致;在 property中似乎选择了怪异的键名使显示更容易,但使所有非显示使用起来更烦人;使用顶级功能对于仅作为实例方法等有意义的内容),但我保留了这些古怪之处,以使其成为您现有类的直接替代品(但在实例上设置了所有按玩家属性,而不是在类上设置,通过 player计算而不是静态设置的派生属性,因为独立的静态属性会增加基本属性和派生属性不同步的几率。

我保留了允许您在不提供任何参数的情况下创建 name的行为,尽管 __init__实际上应该是一个非可选的参数(除非“ Cavalex”是一个通用名称,您可以放心地假设大部分或全部)玩家的名字)。

我意识到当您可以将数据从属性复制到派生属性时,拼出 property并定义 class似乎有点乏味,但是就代码而言,您实际上可以有意义的方式使用而无需极端重复(以及错别字和逻辑错误的伴随风险),了解行为等,这是唯一有意义的方法;一个具有99%类属性的 class(所有方法都有效地忽略了每个实例状态)也可能只是一堆全局变量和顶级函数,而不是

创建类的原因是允许您创建具有不同属性但行为共享的类的许多实例。至少在Python中,多范式语言设计意味着单例模式很少(如果有的话)(并且使用在定义时定义的类级状态删除了类),通过使用纯类级状态使类成为准单例使类毫无意义。模式的唯一优势,将单例的初始化推迟到需要时进行)。

关于python - 无法在Python中使用外部函数更改类变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52335181/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com