You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 09:55:23