MTG卡牌集管理程序开发疑问:对象创建与存储方案咨询
解答你的万智牌集管理程序问题
先直接回应你的两个核心问题:
问题一:不同卡组的同名卡牌实例会被覆盖吗?
不会。你每次调用Card()创建的都是一个独立的对象,哪怕两张卡牌名字相同,它们在内存中是完全分开的实例,各自属于对应的CardSet对象,互相之间不会产生覆盖。不过要注意你当前代码里的add_card方法有问题,会导致卡牌无法被持久存储(后面会详细说)。
问题二:用字典列表存储卡牌是不是更简便合理?
这取决于你的程序需求:
- 如果只是简单存储和读取卡牌数据,用字典列表确实更轻便,代码量更少,不需要定义
Card类。比如每张卡牌用{"card_name": "xxx", "amount": 1, ...}这样的字典表示,直接存在CardSet的列表里。 - 但如果你的程序后续需要扩展功能(比如给卡牌添加计算方法、验证属性合法性、统一处理闪卡/签名逻辑等),用
Card类的面向对象方式会更合理——它能提供类型约束,避免属性拼写错误,也更容易维护和扩展。
你的当前代码存在的几个关键问题
我帮你梳理下代码里的bug,这些问题会导致你的卡牌集无法正常工作:
CardSet.add_card方法缺少self参数:作为类的实例方法,必须把self作为第一个参数,否则无法访问实例的属性。add_card里的cards是局部变量:每次调用add_card都会新建一个空列表,添加完卡牌后返回,但这个列表没有和CardSet实例绑定,导致之前添加的卡牌全部丢失。应该把cards作为CardSet的实例属性,在__init__里初始化。- CSV处理时的逻辑错误:你把
row[3]直接赋值为CardSet对象,之后循环里再判断row[3] not in list_sets就会出错(因为list_sets存的是字符串,而row[3]现在是对象)。应该先提取集合名称字符串,再进行判断。 - 没有处理表头和数据类型转换:CSV文件第一行通常是表头,需要跳过;另外
amount、numb_foil是数字,signed是布尔值,直接读取的字符串需要转换类型。
改进后的代码示例
下面是修正后的代码,解决了上面的问题:
import csv class CardSet: def __init__(self, set_name): self.set_name = set_name self.cards = [] # 用实例属性存储卡牌,持久化保存 def get_set(self): return self.set_name def add_card(self, card_name, card_num, amount, numb_foil, signed): # 创建Card实例并添加到当前卡组的卡牌列表中 card = Card(card_name, card_num, int(amount), int(numb_foil), signed.lower() == 'yes') self.cards.append(card) class Card: def __init__(self, card_name, card_num, amount, numb_foil, signed): self.card_name = card_name self.card_num = card_num self.amount = amount self.numb_foil = numb_foil self.signed = signed def csv_reader(): set_objects = {} # 用字典存储卡组,键为卡组名称,值为卡组对象,查找更高效 with open('Collection.csv', 'rt', encoding='utf8') as f: cards = csv.reader(f) next(cards) # 跳过CSV表头 for row in cards: # 提取各字段,确保索引正确(根据你的注释对应) amount_owned = row[0] card_name = row[2] set_name = row[3] card_num = row[4] foil_owned = row[6] signed = row[7] # 检查卡组是否已存在 if set_name not in set_objects: # 创建新卡组对象 new_set = CardSet(set_name) set_objects[set_name] = new_set # 添加当前卡牌到新卡组 new_set.add_card(card_name, card_num, amount_owned, foil_owned, signed) else: # 找到已存在的卡组,添加卡牌 set_objects[set_name].add_card(card_name, card_num, amount_owned, foil_owned, signed) csv_reader()
额外建议
- 可以给
CardSet添加查找卡牌的方法,比如根据卡牌名称或编号快速查找,避免每次都遍历列表。 - 如果需要统计卡组内的卡牌总数、闪卡占比等,直接在
CardSet类里添加对应的方法即可,面向对象的优势在这里会体现得很明显。
内容的提问来源于stack exchange,提问作者pyRN




