Python copy.deepcopy()失败而不会引发警告,异常或错误

时间:2014-03-28 08:37:19

标签: python debugging copy pyside deep-copy

这个问题与我昨天发布的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提示已准备好接受任何新命令。 / p>

修改

出于某种原因,使用copy()方法代替deepcopy(),如下所示:

function_that_uses_my_new_obj(copy.copy(my_obj))

会导致抛出相同的异常。因此,deepcopy决定停止或被停止并触发执行结束的某些点。我没有得到的是为什么没有提出通知用户......

2 个答案:

答案 0 :(得分:3)

复制和pickle将尝试在所有情况下完成他们的工作,但是对于python中的许多事情,结果的责任仅限于程序员。

为了提高难度:

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

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

  3. 然后有一些副本将在哪些副本上发挥作用并取得成功。对于简单对象,它只包含对前一级别中对象的引用。

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

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

答案 1 :(得分:2)

你断言" my_obj是一个C ++对象"看起来很明显是假的:my_obj实际上是一个python包装器围绕一个C ++对象。所以代码如:

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

只会创建python 包装器的副本,而不会触及底层C ++对象。这解释了为什么尝试调用其中一个复制的包装方法会产生RuntimeError。包装器的副本从未拥有相应的底层C ++对象,因此它的行为就像它已被删除一样。

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