如何重构D&D角色生成器中的重复Python代码?
D&D角色生成器代码重构:消除重复逻辑
问题核心
你当前的character()函数里,每个种族分支都重复执行设置变量+调用race()的操作,冗余代码太多。核心解决思路是用数据驱动替代硬编码的条件判断,把种族属性统一存储,通过用户输入的编号直接匹配对应数据。
重构方案
- 用字典存储所有种族数据:把每个种族的名称、体型、身高范围等属性整理成字典的键值对,一次性定义,避免重复写相同逻辑。
- 简化种族选择逻辑:用户输入编号后,直接从字典中取出对应种族的完整数据,无需一堆
if-elif判断。 - 优化函数参数传递:让
race()函数接收种族数据字典,减少零散参数的传递,代码更整洁。 - 修复文件对象作用域问题:原代码中函数直接依赖全局的
txt对象,改为显式传递文件对象,避免作用域混乱。 - 简化属性掷骰逻辑:用列表推导式简化
stat_roll()的代码,保持功能不变的同时更简洁。
完整重构代码
import random # 定义所有种族的属性数据,数据驱动替代硬编码判断 RACES = { "1": {"name": "Dwarf", "size": "medium", "size_range": "4-5", "age_max": "350", "age_range": "50-300", "speed": "25"}, "2": {"name": "Elf", "size": "medium", "size_range": "5-6", "age_max": "750", "age_range": "100-750", "speed": "30"}, "3": {"name": "Halfling", "size": "small", "size_range": "2-4", "age_max": "250", "age_range": "20-250", "speed": "25"}, "4": {"name": "Human", "size": "medium", "size_range": "5-6", "age_max": "100", "age_range": "15-100", "speed": "30"}, "5": {"name": "Dragonborn", "size": "medium", "size_range": "6-8", "age_max": "80", "age_range": "10-80", "speed": "30"}, "6": {"name": "Gnome", "size": "small", "size_range": "3-4", "age_max": "500", "age_range": "40-500", "speed": "25"}, "7": {"name": "Half-Elf", "size": "medium", "size_range": "5-6", "age_max": "180", "age_range": "20-180", "speed": "30"}, "8": {"name": "Half-Orc", "size": "medium", "size_range": "5-6", "age_max": "75", "age_range": "10-75", "speed": "30"}, "9": {"name": "Tiefling", "size": "medium", "size_range": "5-6", "age_max": "100", "age_range": "15-100", "speed": "30"} } def character(txt): player_name = input("enter your first name! ") character_name = input("enter your characters name! ") # 打印种族选项,直接从RACES字典生成,后续加种族只需改字典 print("what race do you want your character to be?") for num, race_data in RACES.items(): print(f"{num}. {race_data['name']}") character_race_num = input("use the corresponding number to pick: ") # 取对应种族数据,默认用Tiefling(原else分支) race_data = RACES.get(character_race_num, RACES["9"]) # 调用race函数,传递文件对象和种族数据 race(txt, player_name, character_name, race_data) def race(txt, player_name, character_name, race_data): race_name = race_data["name"] print(f"{race_name} live around {race_data['age_max']} years. so i would suggest anywhere between {race_data['age_range']}") player_age = input("input character age: ") print(f"{race_name} sizes are: {race_data['size_range']} feet tall, {race_data['size']}") player_height = input("input character height: ") player_weight = input("input character weight: ") txt.write(f"player name: {player_name}\ncharacter name: {character_name}\nrace: {race_name}\nage: {player_age}\nheight: {player_height}\nweight: {player_weight}\nspeed: {race_data['speed']} feet\n") txt.write("consult the book for items, subraces and stuff. i am tired and dont know how to make this better, will make it better later.\n") def stat_roll(txt): '''this will make a list of stats for the 4d6 rolls, then remove the lowest number, then add them up.''' # 用列表推导式简化掷骰逻辑 stat_list = [random.randint(1,6) for _ in range(4)] stat_list.remove(min(stat_list)) stat_sum = sum(stat_list) txt.write(f"{str(stat_sum)}\n") # 主程序流程 with open("dnd_character.txt", "w") as txt: character(txt) txt.write("these are the stats of your character!\n") for _ in range(6): stat_roll(txt)
重构亮点
- 后续新增种族只需在
RACES字典里加一行数据,无需修改任何函数逻辑,扩展性极强。 - 消除了几十行重复的
if-elif代码,可读性和维护性大幅提升。 - 函数依赖更清晰,通过参数传递文件对象,避免全局变量带来的潜在问题。
- 掷骰逻辑用列表推导式简化,代码更紧凑但功能不变。
内容的提问来源于stack exchange,提问作者WeaselBug01
相关产品推荐
相关产品推荐

