每次调用一个键时,一个 return 如何从字典中随机数?

How does one return a random number from a dictionary every time a key is called?

我正在尝试制造一种提供随机伤害的武器。我这样做是使用

形式的项目数据库
itemsList = {
1: {"name": "Padded Armor",  "armor": 1,  "value": 5, "class": "Light"},
2: {"name": "Leather Armor",  "armor": 2,  "value": 10, "class": "Light"},
....
19: {"name": "Dagger", "damage" : int(random.randrange(1, 4)), "value": 2, "Type": "Dagger"},
20: {"name": "Dagger + 1", "damage" : int(random.randrange(1, 4) + 1), "value": 200, "Type": "Dagger"},
21: {"name": "Dagger + 2", "damage" : int(random.randrange(1, 4) + 2), "value": 750, "Type": "Dagger"},
22: {"name": "Dagger + 3", "damage" : int(random.randrange(1, 4) + 3), "value": 2000, "Type": "Dagger"}
}

每次我尝试调用 "damage" 它只是 returns 相同的结果。我知道这是因为随机数是生成一个然后保存到那个字典键。

每次调用损坏时我将如何生成一个随机数?

您可以在字典中存储一个生成随机数的函数,而不是随机数本身。 (顺便说一下,如果你的字典的键只是连续的整数,请考虑使用列表。)

from random import randrange    
itemsList = [
  {"name": "Padded Armor",  "armor": 1,  "value": 5, "class": "Light"},
  {"name": "Leather Armor",  "armor": 2,  "value": 10, "class": "Light"},
  ....
  {"name": "Dagger", "damage": lambda: randrange(1, 4), "value": 2, "Type": "Dagger"},
  {"name": "Dagger + 1", "damage": lambda: randrange(1, 4) + 1, "value": 200, "Type": "Dagger"},
  {"name": "Dagger + 2", "damage": lambda: randrange(1, 4) + 2, "value": 750, "Type": "Dagger"},
  {"name": "Dagger + 3", "damage": lambda: randrange(1, 4) + 3, "value": 2000, "Type": "Dagger"}
]

然后,您只需调用该函数即可获得实际伤害掷骰:

# Roll damage for a dagger + 3
damage = itemsList[22]["damage"]()

我会不厌其烦地在 class 的 itemsList 个实例中制作这些东西。尽管您可能认为这有点矫枉过正,但这样做会给您以后的编程带来很大的灵活性。它还将使许多代码更易于编写(和阅读),因为您将能够使用点符号而不是通过索引来引用事物,这意味着您不仅可以写入现在使用 itemsList[19].damage 而不是 itemsList[19]["damage"]。您还将对 itemsList[1].nameitemsList[2].value 等所有其他属性使用相同的语法,并且能够编写如下条件代码:

if hasattr(itemsList[2], 'Class'):
    # do something based on itemsList[2].Class

我的意思是:

import random

class Gear(object):
    def __init__(self, **kwargs):
        kwargs['_damage'] = kwargs.pop('damage', False)
        self.__dict__.update(kwargs)

    @property
    def damage(self):
        return int(random.randrange(*self._damage)) if self._damage else 0

itemsList = {
    1: Gear(name="Padded Armor", armor=1, value=5, Class="Light"),
    2: Gear(name="Leather Armor", armor=2, value=10, Class="Light"),
    # ...
    19: Gear(name="Dagger", damage=(1, 4), value=2, Type="Dagger"),
    20: Gear(name="Dagger + 1", damage=(1, 5), value=200, Type="Dagger"),
    21: Gear(name="Dagger + 2", damage=(1, 9), value=750, Type="Dagger"),
    22: Gear(name="Dagger + 3", damage=(2, 6), value=2000, Type="Dagger"),
}

在下面的一条评论中回答您的后续问题:

kwargs 是传递给 __init__() 构造方法的所有关键字参数的字典。 (__dict__ 是字典的名称,每个实例都在其中存储其属性。)请参阅文档中的 this section

damage 由 class 使用 @property decorator which is a simple way to actualy make it a "data descriptor". This sets things up so that whenever you reference a class instance's damage attribute, it will call a function to retrieve/determine its current "value". See the Descriptor HowTo Guide 定义,以获取有关 Python 描述符的更多信息。

您可能会发现它减少了代码中的重复,只在您的字典中存储损坏权重(在我的代码中仍称为 damage),并有一个单独的函数来计算实际损坏。例如

from random import randint

itemsList = {
1: {"name": "Padded Armor",  "armor": 1,  "value": 5, "class": "Light"},
2: {"name": "Leather Armor",  "armor": 2,  "value": 10, "class": "Light"},
19: {"name": "Dagger", "damage" : 0, "value": 2, "Type": "Dagger"},
20: {"name": "Dagger + 1", "damage" : 1, "value": 200, "Type": "Dagger"},
21: {"name": "Dagger + 2", "damage" : 2, "value": 750, "Type": "Dagger"},
22: {"name": "Dagger + 3", "damage" : 3, "value": 2000, "Type": "Dagger"}
}

def getdamage(item):
    return randint(1, 4) + item['damage']

# test code
for i in range(20):

    item = randint(19, 21)
    damage = getdamage(itemsList[item])
    print("I used item %d and made damage %d" % (item, damage))

现在您的随机函数只在一个地方,如果您决定稍后更改它,工作量会减少。

我不明白的一件事是为什么将盔甲和武器放在一个列表中?您可以将某些盔甲的索引传递给损坏函数并得到一个错误。