简体   繁体   English

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

[英]Python copy.deepcopy() fails without raising warning, exception or error

This question is related to another question I posted yesterday, although it is much more general in nature. 这个问题与我昨天发布的另一个问题有关,尽管它本质上更为笼统。

Because of the thread I mentionned, I have been trying to determine what objects can be copied, pickled, marshaled and what objects cannot. 由于我提到的线程,我一直在尝试确定哪些对象可以被复制,pickle,marshaled以及哪些对象不能。

While doing that, I stumbled on this puzzle: 在这样做时,我偶然发现了这个难题:

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

throws: 抛出:

  function_that_uses_my_new_obj(new_obj) 

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

Now, since my_obj is a C++ object, that error I can understand. 现在,由于my_obj 一个C++对象,我可以理解这个错误。 And the reason for that particular problem is the main topic of the other thread. 而这个特定问题的原因是另一个主题的主题。

However, when I try: 但是,当我尝试:

function_that_uses_my_new_obj(copy.deepcopy(my_obj))

I don't get anything at all . 我什么都没得到 The program runs normally to this line, stops there for a few seconds and the execution is stopped, the code after that line is not run, no exception/error/warning is thrown and the Python prompt is ready to accept any new command. 程序正常运行到此行,在那里停止几秒钟并且执行停止,该行之后的代码没有运行,没有抛出异常/错误/警告,并且Python提示已准备好接受任何新命令。

EDIT 编辑

For some reason, using the copy() method instead of deepcopy() like so: 出于某种原因,使用copy()方法而不是deepcopy()如下所示:

function_that_uses_my_new_obj(copy.copy(my_obj))

results in the same exception being thrown. 导致抛出相同的异常。 So there has to be some point at which deepcopy decides to stop or is being stopped and that triggers the end of the execution. 因此必须要有一些观点,即deepcopy决定停止或正在停止并触发执行的结束。 What I don't get is why nothing is raised to inform the user... 我没有得到的是为什么没有提出通知用户...

Copy and pickle will try to do their job in all cases, but as for many things in python, the responsibility of the result is placed on the programmer only. 复制和pickle将尝试在所有情况下完成他们的工作,但是对于python中的许多事情,结果的责任仅仅放在程序员身上。

In order of rising difficulty: 为了增加难度:

  1. The objects that really can be safely copied or pickled are basically the primitive types, strings, lists, dictionaries, numbers, etc. 真正可以安全复制或腌制的对象基本上是原始类型,字符串,列表,字典,数字等。

  2. Then there are many objects that explicitly support the magic methods (like __copy__ and __deepcopy__ ) 然后有许多对象明确支持魔术方法(如__copy____deepcopy__

  3. Then there are the objects on which copy will do its best and succeed. 然后有一些副本将在哪些副本上发挥作用并取得成功。 For simple objects, that contain only references to objects in the previous levels. 对于简单对象,它仅包含对先前级别中对象的引用。

  4. Finally the really unsafe to copy: 最后复制真的不安全:

    • Large object graphs with many circular references 带有许多循环引用的大对象图
    • Object that are being used and modified by other threads. 由其他线程使用和修改的对象。
    • Object with external resources: files, connections, etc. 具有外部资源的对象:文件,连接等
    • Object that wrap or proxy C libraries 包装或代理C库的对象

Your assertion that "my_obj is a C++ object" looks pretty obviously false: my_obj is actually a python wrapper around a C++ object. 你的断言“my_obj是一个C ++对象”看起来非常明显错误: my_obj实际上是一个围绕 C ++对象的python包装器。 So code such as: 所以代码如:

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

will only create a copy of the python wrapper , leaving the underlying C++ object untouched. 将只创建python 包装器的副本,保持底层C ++对象不变。 This explains why attempting to call one of the copied wrapped methods will produce that RuntimeError. 这解释了为什么尝试调用其中一个复制的包装方法会产生RuntimeError。 The copy of the wrapper never had a corresponding underlying C++ object, and so it behaves as if it has been deleted. 包装器的副本从来没有相应的底层C ++对象,因此它的行为就像它已被删除一样。

This kind of thing can happen quite easily in "normal" PySide/PyQt code. 在“普通”PySide / PyQt代码中,这种事情很容易发生。 Sometimes, if you don't take care to keep a reference to an object on the python side, Qt can delete the C++ part, leaving you with an "empty" wrapper. 有时,如果你不小心保持对python端对象的引用,Qt可以删除C ++部分,留下一个“空”包装器。 And in such situations, you will see the exact same RuntimeError. 在这种情况下,您将看到完全相同的RuntimeError。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM