这个问题与我昨天发布的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
决定停止或被停止并触发执行结束的某些点。我没有得到的是为什么没有提出通知用户......
答案 0 :(得分:3)
复制和pickle将尝试在所有情况下完成他们的工作,但是对于python中的许多事情,结果的责任仅限于程序员。
为了提高难度:
真正可以安全复制或腌制的对象基本上是原始类型,字符串,列表,字典,数字等。
然后有许多明确支持魔术方法的对象(如__copy__
和__deepcopy__
)
然后有一些副本将在哪些副本上发挥作用并取得成功。对于简单对象,它只包含对前一级别中对象的引用。
最后复制真的不安全:
答案 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。