英文:
how to use dictionaries to store multiple functions with different argument requirements
问题
我正在尝试构建一个类似以下结构的字典(用于一个有趣的项目):
_cardLibrary = {
1: {'name': 'Strike',
'cost': 1,
'type': 'attack',
'rarity': 'common',
'action': [deal_damage]
},
2: {'name': 'Defend',
'cost': 1,
'type': 'skill',
'rarity': 'common',
'action': [give_block]
},
3: {'name': 'Bash',
'cost': 2,
'type': 'attack',
'rarity': 'common',
'action':
[deal_damage,
apply_status]
}
}
我想要创建一个名为 "use(i)" 的函数,它接受特定的卡片并执行存储在 'action' 中的代码。正如您在第三个元素中所看到的,'action' 应该能够包含多个函数,每个函数都需要特定的参数。
例如,deal_damage 需要3个参数,apply_status 需要4个参数。
deal_damage(caster, target, basedamage)
apply_status(caster, target, status, intensity)
是否有一种方法可以创建一个函数,调用存储在每个特定卡片内的所有函数?
我还需要一种方法来传递实际参数给每一个函数... 一些参数可以是常量值。比如,对于特定的卡片,status 始终为1,intensity 为1。然而,caster 和 target 需要在初始的 use(caster, target) 函数中定义...
到目前为止,我已经尝试遍历每个函数,但这让我无法传递具体的参数给每个函数...
我还尝试了这个链接:https://stackoverflow.com/questions/64043601/python-iterate-through-functions-with-different-arguments
但出于某种原因,我无法让代码运行起来。
如果这完全不起作用,我正在考虑将每张卡片都变成一个函数本身,但这对其他原因来说也是有问题的... 特别是关于可扩展性的问题。
有关如何处理这个问题的任何想法吗?
谢谢大家。
英文:
I'm trying to build a dictionary that looks like this (for a fun project):
_cardLibrary = {
1: {'name': 'Strike',
'cost': 1,
'type': 'attack',
'rarity': 'common',
'action': [deal_damage]
},
2: {'name': 'Defend',
'cost': 1,
'type': 'skill',
'rarity': 'common',
'action': [give_block]
},
3: {'name': 'Bash',
'cost': 2,
'type': 'attack',
'rarity': 'common',
'action':
[deal_damage,
apply_status]
}
}
I'd like to build a function " use(i) " which takes the specific card and executes the code stored inside of 'action'. As you can see in the third element, 'action' should be able to contain multiple functions, each of them requiring specific arguments.
For instance, deal_damage requires 3 arguments. Apply status requires 4.
deal_damage(caster, target, basedamage)
apply_status(caster, target, status, intensity)
Is there any way to create a function that calls all the functions stored inside every specific card?
I would also need some way to be able to pass the actual arguments to every one of the functions... Some of the arguments could be constant values. Like, for this specific card, status is always 1 and intensity is 1. However, target and caster really need to be defined in the initial use(caster, target) function...
So far, I've tried to iterate over every single function, however, this leaves me with the problem of not being able to pass the concrete arguments to every function...
I also tried this link: https://stackoverflow.com/questions/64043601/python-iterate-through-functions-with-different-arguments
but for some reason, iIcannot make the code work
If this doesn't work at all, I was considering the possibility of making every single card a function itself, however, this is problematic for other reasons... specifically regarding scalability.
Any ideas on how can I approach this?
thank you all
答案1
得分: 0
你可以使用functools.partial
来预定义每个函数的一些参数。然后,在调用这些函数时,你只需要指定caster
和target
参数:
from functools import partial
def deal_damage(caster, target, basedamage):
print(f"{caster} dealt {basedamage} damage to {target}")
def give_block(caster, target, defense):
print(f"{caster} blocked {defense} damage from {target}")
def apply_status(caster, target, status, intensity):
print(f"{caster} applied {intensity}x{status} to {target}")
_cardLibrary = {
"strike": {'name': 'Strike',
'cost': 1,
'type': 'attack',
'rarity': 'common',
'actions': [partial(deal_damage, basedamage=10)]
},
"defend": {'name': 'Defend',
'cost': 1,
'type': 'skill',
'rarity': 'common',
'actions': [partial(give_block, defense=5)]
},
"bash": {'name': 'Bash',
'cost': 2,
'type': 'attack',
'rarity': 'common',
'actions':
[partial(deal_damage, basedamage=5),
partial(apply_status, status='stun', intensity=5)]
}
}
注意,我将字典的键更改为字符串,并将每张卡片中的'action'
键更改为'actions'
,因为每张卡片可以有多个动作。
然后,在你的游戏循环中,你可以像调用常规函数一样调用这些partial
对象:
while True:
print(f"You have {len(_cardLibrary)} cards: ")
print(", ".join(_cardLibrary))
u_in = input("What would you like to do? (or quit)").lower()
if u_in == "quit":
print("Goodbye")
break
try:
card = _cardLibrary[u_in]
except KeyError:
print("Invalid choice. Please choose again")
continue
print(f"You played the {card['name']} card")
for action in card['actions']:
print("ACTION: ", end="")
action(caster="You", target="Enemy")
这会产生以下输出:
You have 3 cards:
strike, defend, bash
What would you like to do? (or quit) strike
You played the Strike card
ACTION: You dealt 10 damage to Enemy
You have 3 cards:
strike, defend, bash
What would you like to do? (or quit) bash
You played the Bash card
ACTION: You dealt 5 damage to Enemy
ACTION: You applied 5xstun to Enemy
You have 3 cards:
strike, defend, bash
What would you like to do? (or quit) defend
You played the Defend card
ACTION: You blocked 5 damage from Enemy
You have 3 cards:
strike, defend, bash
What would you like to do? (or quit) quit
Goodbye
英文:
You could use functools.partial
to pre-define some arguments to each function. Then, when you need to call the functions, you will only need to specify the caster
and target
arguments:
from functools import partial
def deal_damage(caster, target, basedamage):
print(f"{caster} dealt {basedamage} damage to {target}")
def give_block(caster, target, defense):
print(f"{caster} blocked {defense} damage from {target}")
def apply_status(caster, target, status, intensity):
print(f"{caster} applied {intensity}x{status} to {target}")
_cardLibrary = {
"strike": {'name': 'Strike',
'cost': 1,
'type': 'attack',
'rarity': 'common',
'actions': [partial(deal_damage, basedamage=10)]
},
"defend": {'name': 'Defend',
'cost': 1,
'type': 'skill',
'rarity': 'common',
'actions': [partial(give_block, defense=5)]
},
"bash": {'name': 'Bash',
'cost': 2,
'type': 'attack',
'rarity': 'common',
'actions':
[partial(deal_damage, basedamage=5),
partial(apply_status, status='stun', intensity=5)]
}
}
Note that I changed the keys of the dictionary to strings, and the 'action'
key in each card to 'actions'
because there can be multiple actions per card.
Then, in your game loop, you can call these partial
objects like a regular function:
while True:
print(f"You have {len(_cardLibrary)} cards: ")
print(", ".join(_cardLibrary))
u_in = input("What would you like to do? (or quit) ").lower()
if u_in == "quit":
print("Goodbye")
break
try:
card = _cardLibrary[u_in]
except KeyError:
print("Invalid choice. Please choose again")
continue
print(f"You played the {card['name']} card")
for action in card['actions']:
print("ACTION: ", end="")
action(caster="You", target="Enemy")
This gives the following output:
You have 3 cards:
strike, defend, bash
What would you like to do? (or quit) strike
You played the Strike card
ACTION: You dealt 10 damage to Enemy
You have 3 cards:
strike, defend, bash
What would you like to do? (or quit) bash
You played the Bash card
ACTION: You dealt 5 damage to Enemy
ACTION: You applied 5xstun to Enemy
You have 3 cards:
strike, defend, bash
What would you like to do? (or quit) defend
You played the Defend card
ACTION: You blocked 5 damage from Enemy
You have 3 cards:
strike, defend, bash
What would you like to do? (or quit) quit
Goodbye
答案2
得分: 0
你可以让所有的函数参数列表以 ,**_
结尾,这样它们可以接收(并忽略)它们实际上不处理的参数。 这将允许你直接将固定值参数添加到 _cardLibrary
字典中,并将其用作函数的参数。然后定义你的 use()
函数,将它自己的命名参数列表添加到字典的固定值作为覆盖:
def deal_damage(caster, target, basedamage, **_):
# ...
def use(card, **kwargs):
for function in _cardLibrary[card]['action']:
function({**_cardLibrary[card], **kwargs})
用法:
use(1, caster="orc", target="human")
# 假设 _cardLibrary 为卡片 #1 提供了 "baseDamage" 的默认值
英文:
You could make all your function parameter lists end with ,**_
which will let them receive (and ignore) parameters they're not actually processing. This will allow you to add fixed value parameters directly in the _cardLibrary
dictionary and use it as parameters to the functions. Then define you use()
function to add its own list of named arguments to the dictionary's fixed values as an override:
def deal_damage(caster,target,basedamage,**_):
# ...
def use(card, **kwargs):
for function in _cardLibrary[card]['action']:
function(**{**_cardLibrary[card],**kwargs})
usage:
use(1,caster="orc",target="human")
# assuming _cardLibrary supplies the default value for "baseDamage" on card #1
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论