【问题标题】:Python copy.deepcopy() fails without raising warning, exception or errorPython copy.deepcopy() 失败且未引发警告、异常或错误
【发布时间】:2014-03-28 08:37:18
【问题描述】:

这个问题与我昨天发布的another question 有关,虽然它本质上更笼统。

由于我提到的线程,我一直在尝试确定哪些对象可以复制、腌制、封送,哪些对象不能。

在此过程中,我偶然发现了这个谜题:

new_obj = copy.deepcopy(my_obj)
function_that_uses_my_new_obj(new_obj)

抛出:

    function_that_uses_my_new_obj(new_obj)

RuntimeError: 内部 C++ 对象 (Pyside.QtGui.QWidget) 已删除

现在,由于 my_obj 一个 C++ 对象,我可以理解这个错误。这个特定问题的原因是另一个线程的主题。

但是,当我尝试时:

function_that_uses_my_new_obj(copy.deepcopy(my_obj))

我什么都没得到。程序正常运行到这一行,停在那里几秒钟并停止执行,该行之后的代码没有运行,没有抛出异常/错误/警告,Python提示符准备接受任何新命令。

编辑

由于某种原因,使用copy() 方法而不是deepcopy() 像这样:

function_that_uses_my_new_obj(copy.copy(my_obj))

导致抛出相同的异常。所以必须有某个时刻deepcopy 决定停止或正在停止并触发执行结束。我不明白为什么没有提出任何通知用户...

【问题讨论】:

    标签: python debugging copy pyside deep-copy


    【解决方案1】:

    Copy 和 pickle 在所有情况下都会尝试完成它们的工作,但是对于 python 中的许多事情,结果的责任只放在程序员身上。

    按照难度递增的顺序:

    1. 真正可以安全复制或腌制的对象基本上是原始类型、字符串、列表、字典、数字等。

    2. 然后有很多对象明确支持魔术方法(如__copy____deepcopy__

    3. 然后是复制将尽力而为并成功的对象。对于简单对象,仅包含对先前级别中对象的引用。

    4. 最后复制真的不安全:

      • 具有许多循环引用的大型对象图
      • 其他线程正在使用和修改的对象。
      • 具有外部资源的对象:文件、连接等
      • 包装或代理 C 库的对象

    【讨论】:

    • 感谢您的回答。我认为@ekhumoro 找到了意外行为背后的原因,但你的仍然很有趣
    【解决方案2】:

    您关于“my_obj 是 C++ 对象”的断言看起来很明显是错误的:my_obj 实际上是一个 Python 包装器围绕一个 C++ 对象。所以代码如:

        widget = QtGui.QWidget()
        my_obj = copy.deepcopy(widget)
    

    只会创建python wrapper 的副本,而底层C++ 对象保持不变。这解释了为什么尝试调用复制的包装方法之一会产生 RuntimeError。包装器的副本从来没有对应的底层 C++ 对象,因此它的行为就像它已被删除一样。

    这种事情在“正常”的 PySide/PyQt 代码中很容易发生。有时,如果您不注意在 python 端保留对对象的引用,Qt 可以删除 C++ 部分,给您留下一个“空”包装器。在这种情况下,您会看到完全相同的 RuntimeError。

    【讨论】:

    • 我明白了,谢谢。我认为这更像是另一个线程的答案。如果你也在那里发布,我也会接受它作为答案。
    • 我的意思是“也”而不是“更多”
    • 我遇到了类似的问题,试图复制和深度复制 QObject 的子类(有时您会这样做以获取信号或 tr()。)症状是“RuntimeError: super-class __init__() of从未调用过 FOO 类型。”这也可能是 PyQt 退出 bug 崩溃的原因。另请注意,Python3 在复制时引发了异常,而 Python2 没有。所以谢谢,这个答案有帮助。
    猜你喜欢
    • 1970-01-01
    • 2017-11-18
    • 2016-03-12
    • 1970-01-01
    • 2017-05-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多