如何在curses窗口中深拷贝包含窗口对象的Room实例?
错误原因
深拷贝失败的核心原因是:copy.deepcopy() 依赖Python的pickle序列化机制复制对象,但curses库的_curses.window(即代码中的pad对象)是底层C实现的系统资源句柄,这类对象不支持pickle序列化。当深拷贝尝试处理Room类中的self.bg和self.pad属性时,就会抛出TypeError: cannot pickle '_curses.window' object错误。
解决方案
1. 自定义__deepcopy__方法,手动控制拷贝逻辑
在Room类中实现__deepcopy__方法,跳过对原有pad对象的拷贝,基于原对象参数重新创建新的pad实例,确保每个拷贝的Room拥有独立的资源句柄:
import curses from curses import wrapper import copy def main(stdscr): bg = Background(100, 237) test_room = Room(10, 15, bg) new_room = copy.deepcopy(test_room) print("Test deepcopy: ", new_room.height, new_room.width) class Background(): def __init__(self, height, width): self.height = height self.width = width self.pad = curses.newpad(self.height, self.width) class Room(): def __init__(self, height, width, background): self.height = height self.width = width # 保存background参数,方便拷贝时重建pad self.bg_height = background.height self.bg_width = background.width self.bg = background.pad self.pad = background.pad.subpad(self.height, self.width) def __deepcopy__(self, memo): # 创建新的Background实例 new_bg = Background(self.bg_height, self.bg_width) # 创建新的Room实例并关联新Background new_room = Room(self.height, self.width, new_bg) # 记录已拷贝对象,避免循环引用 memo[id(self)] = new_room return new_room while True: curses.wrapper(main)
2. 使用工厂函数创建独立Room实例
放弃深拷贝,用工厂函数封装Room的创建逻辑,每次需要新Room时,用初始参数重新生成实例,确保每个Room的pad都是独立新对象:
import curses from curses import wrapper def create_room(height, width, bg_height, bg_width): bg = Background(bg_height, bg_width) return Room(height, width, bg) def main(stdscr): # 定义初始参数 bg_h, bg_w = 100, 237 room_h, room_w = 10, 15 # 创建第一个Room test_room = create_room(room_h, room_w, bg_h, bg_w) # 创建第二个独立Room new_room = create_room(room_h, room_w, bg_h, bg_w) print("Test factory: ", new_room.height, new_room.width) class Background(): def __init__(self, height, width): self.height = height self.width = width self.pad = curses.newpad(self.height, self.width) class Room(): def __init__(self, height, width, background): self.height = height self.width = width self.bg = background.pad self.pad = background.pad.subpad(self.height, self.width) while True: curses.wrapper(main)
3. 重构Room的属性存储逻辑
修改Room类,不直接持有pad对象,而是保存创建pad所需的参数,在需要使用时动态初始化,深拷贝时仅复制参数即可:
import curses from curses import wrapper import copy def main(stdscr): bg = Background(100, 237) test_room = Room(10, 15, bg) new_room = copy.deepcopy(test_room) # 按需初始化pad new_room.init_pads() print("Test refactor: ", new_room.height, new_room.width) class Background(): def __init__(self, height, width): self.height = height self.width = width self.pad = curses.newpad(self.height, self.width) class Room(): def __init__(self, height, width, background): self.height = height self.width = width # 保存创建pad的参数,而非pad对象 self.bg_params = (background.height, background.width) self.bg = None self.pad = None def init_pads(self): # 动态初始化pad bg = Background(*self.bg_params) self.bg = bg.pad self.pad = bg.pad.subpad(self.height, self.width) while True: curses.wrapper(main)
内容的提问来源于stack exchange,提问作者JD Allen
相关产品推荐
相关产品推荐

