gpt4 book ai didi

python - python如何在 ' for'循环中处理对象实例化

转载 作者:太空狗 更新时间:2023-10-29 22:03:43 26 4
gpt4 key购买 nike

我有一个非常复杂的类:

class C:
pass

我有这个测试代码:

for j in range(10):
c = C()
print c

给出:

<__main__.C instance at 0x7f7336a6cb00>
<__main__.C instance at 0x7f7336a6cab8>
<__main__.C instance at 0x7f7336a6cb00>
<__main__.C instance at 0x7f7336a6cab8>
<__main__.C instance at 0x7f7336a6cb00>
<__main__.C instance at 0x7f7336a6cab8>
<__main__.C instance at 0x7f7336a6cb00>
<__main__.C instance at 0x7f7336a6cab8>
<__main__.C instance at 0x7f7336a6cb00>
<__main__.C instance at 0x7f7336a6cab8>

可以很容易地看出 Python 在两个不同的值上切换。在某些情况下,这可能是灾难性的(例如,如果我们将对象存储在其他一些复杂对象中)。

现在,如果我将对象存储在列表中:

lst = []
for j in range(10):
c = C()
lst.append(c)
print c

我明白了:

<__main__.C instance at 0x7fd8f8f7eb00>
<__main__.C instance at 0x7fd8f8f7eab8>
<__main__.C instance at 0x7fd8f8f7eb48>
<__main__.C instance at 0x7fd8f8f7eb90>
<__main__.C instance at 0x7fd8f8f7ebd8>
<__main__.C instance at 0x7fd8f8f7ec20>
<__main__.C instance at 0x7fd8f8f7ec68>
<__main__.C instance at 0x7fd8f8f7ecb0>
<__main__.C instance at 0x7fd8f8f7ecf8>
<__main__.C instance at 0x7fd8f8f7ed40>

这解决了这个问题。

所以现在,我必须问一个问题......有谁能用复杂的词(我的意思是,深入地)解释 Python 如何处理对象引用?我想,这是一个优化问题(节省内存,或防止泄漏,...)

非常感谢。

编辑:好的,让我们更具体一点。我很清楚 python 有时必须收集垃圾......但是,就我而言:

我有一个由 Cython 定义的类返回的列表:管理“节点列表”的“网络”类(网络和节点类都在 Cython 扩展 中定义)。每个节点都有一个对象 [然后转换为 (void *)] 'userdata' 对象。 Nodes 列表是从 cython 内部填充的,而 UserData 是在 Python 脚本中填充的。所以在 python 中,我有以下内容:

...
def some_python_class_method(self):
nodes = self.netBinding.GetNetwork().get_nodes()
...
for item in it:
a_site = PyLabSiteEvent()
#l_site.append(a_site) # WARN : Required to get an instance on 'a_site'
# that persits - workaround...
item.SetUserData(a_site)

稍后在同一个 python 类中使用同一个 cython getter 重用这个节点列表:

def some_other_python_class_method(self, node):
s_data = node.GetUserData()
...

因此,似乎在节点列表的 UserDatas 中进行存储后,我的 python 脚本完全失明并且正在释放/重用内存。它通过使用附加列表(此处:'l_site')第二次引用(但显然是 python 端的第一次引用)来工作。这就是为什么我必须更多地了解 Python 本身,但似乎我在 Python 和 Cython 之间实现通信的方式是导致我不得不面对的问题的原因。

最佳答案

这里不需要“复杂”:在第一个示例中,您没有保留对名称“c”引用的对象的其他引用 - 当在循环的后续迭代中运行“c = C()”行中的代码时,先前保存在“c”中的一个引用“丢失了。

由于标准 Python 使用引用计数来跟踪何时应该从内存中删除对象,因为此时前一个循环交互的对象的引用计数达到 0,它被销毁,并且它的内存可用于其他对象。

为什么你有 2 个变化的值?因为此时创建新迭代中的对象——即当Python执行c = C()=右边的表达式时,对象先前的迭代仍然存在,由名称 c 引用 - 因此新对象是在另一个内存位置构造的。 Python 然后继续将新对象分配给 c,此时前一个对象如上所述被销毁 - 这意味着在下一次(第 3 次)迭代中,该内存将可用于新对象C 的实例。

在第二个例子中,新创建的对象永远不会丢失引用,因此它们的内 stub 本不会被释放——新对象总是占用一个新的内存位置。

最重要的是:使用高级语言(如 Python 或其他语言)的目的是不必担心内存分配。语言会为您解决这个问题。在这种情况下,正如您注意到的那样,CPython(标准)实现做了正确的事情。 Pypy 或 Jython 等其他实现在上述示例中的每个实例的“内存位置”方面可能具有完全不同的行为,但所有符合要求的实现(包括这 3 个)从“观点”来看将表现完全相同Python 程序:(1) 它确实可以访问它保留引用的实例,(2) 这些实例的数据无论如何都没有损坏或损坏。

关于python - python如何在 ' for'循环中处理对象实例化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12831280/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com