如何在函数内通过类getattr方式获取局部变量?locals()是否合规?
locals()的合理性疑问 初始测试示例的问题
我想实现如下功能的函数:
def func(var_name): x = 2 y = 3 return getattr(self, var_name)
调用func("x")时希望返回2,但显然问题在于函数调用时未传入self,无法通过getattr获取函数内的变量。我之前试过一个解决方案,但它返回的是函数本身而非调用时的实例,根本访问不到函数运行时计算的变量。
实际场景:宝可梦战斗的攻击反馈效果处理
我正在开发一款宝可梦战斗游戏,需要解决攻击对使用者产生反馈效果的编码问题——比如攻击有概率触发Moxie(干劲)提升的情况。
我的初始方案是给攻击对象添加一个包含BackEffect对象的列表属性。这些BackEffect对象包含执行效果的do()函数、执行时机信息,以及do()所需的参数(不同效果需要访问不同信息,比如Moxie提升效果需要在攻击使对方宝可梦昏厥时执行)。execute_attack()函数会遍历这个列表,调用所有符合执行时机的do函数。
但随着效果种类增多,这套方案变得越来越冗余:
def execute_attack(attack, pokemon): # 执行其他战斗逻辑,生成后续用到的变量 attacker = attack.attacking_pokemon for b in attack.back_effects: if b.effect_type == "needs to know if hit": b.do(attacker, did_it_hit) elif b.effect_type == "needs to know if fainted": b.do(attacker, did_it_faint) elif b.effect_type == "needs to know how much damage": b.do(attacker, how_much_damage)
每新增一种效果,就得多加一个elif分支,重复度极高。我想找到一种不用修改execute_attack()就能新增BackEffect的方案——只要相关变量已经在execute_attack()中可用就行。
对于对象来说,getattr()可以实现类似的动态获取逻辑,但把所有变量放进字典的方案并不理想:要么把execute_attack()内的所有内容都塞进字典,要么新增效果时就得修改函数把更多变量移进去,导致这个函数越来越臃肿;此外,日常频繁使用的大量无关变量都要从同一个字典里获取,会让非反馈效果的处理代码变得混乱不堪。
locals()看起来没有这些问题,对我的特定场景而言似乎是更优解。我知道如果从execute_attack()中请求意外的变量可能会引发问题,但可请求的变量列表是固定的,所以这对我来说应该不是问题。我只是不想在已经很长的execute_attack()里用高度重复的方式实现逻辑,同时也想简化新效果的开发流程。
核心疑问
那么在我的场景中使用locals()仍属于不良实践吗?如果是,原因是什么?
(补充:我最初没提供这些细节是因为上一个问题因添加了不必要的细节而反响不佳)
内容的提问来源于stack exchange,提问作者Zoe Allen

