python如何在for循环中处理对象实例化 [英] How python handles object instantiation in a ' for' loop

查看:79
本文介绍了python如何在for循环中处理对象实例化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的课堂非常复杂:

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启用了两个不同的值.在某些情况下,这可能是灾难性的(例如,如果我们将对象存储在其他复杂的对象中).

One can easily see that Python switches on two different values. In some cases, this can be catastrophic (for example if we store the objects in some other complex object).

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

Now, if I store the objects in a List :

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在对象引用中的表现吗?我想,这是一个优化问题(以节省内存或防止泄漏……)

So now, I have to ask a question... Does anyone could explain with complex words (I mean, deeply) how Python behave with the objects references ? I suppose, it is a matter of optimization (to spare memory, or prevent leaks, ...)

非常感谢.

好的,让我们更具体些.我很清楚python有时不得不收集垃圾...但是,就我而言:

EDIT : Ok so, let's be more specific. I'm quite aware that python has to collect garbage sometimes... But, in my case :

我有一个Cython定义的类返回的列表:类"Network",用于管理节点"的列表(Network和Node类均在 Cython扩展中定义).每个节点都有一个对象[然后强制转换为(void *)]'userdata'对象.从cython内部填充Nodes列表,而在Python脚本内部填充UserData.所以在python中,我有以下内容:

I had a list returned by a Cython defined class : class 'Network' that manages a 'Node's list (both Network and Node class are defined in a Cython extension). Each Node has a an object [then casted into (void *)] 'userdata' object. The Nodes list is populated from inside cython, while the UserData are populated inside the Python script. So in python, I had the following :

...
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)

稍后使用相同的cython getter在相同的python类中重用此节点列表:

Reusing this node list later on in the same python class using the same cython getter :

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

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

So, it seems that with the storage made in the node list's UserDatas, my python script was completely blind and was freeing/reusing memory. It worked by referencing a second time (but apparently a first one for python side), using an additional list (here : 'l_site'). This is why I had to know a bit more about Python itself, but it seems that the way I implemented the communication between Python and Cython is responsible for the issues a had to face.

推荐答案

此处无需复杂":在第一个示例中,您没有保留对名称"c"引用的对象的其他引用-在循环的后续迭代中在"c = C()"行中运行代码时,该引用先前保存在"c"中"丢失了.

There is no need to be "complex" here: In the first example, you keep no other reference to the object referenced by the name "c" - when running the code in the line "c = C()" on subsequent iterations of the loop, the one reference previously held in "c" is lost.

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

Since standard Python uses reference counting to keep track of when it should delete objects from memory, as at this moment the reference counting for the object of the previous loop interation reaches 0, it is destroyed, and its memory is made available for other objects.

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

Why do you have 2 changing values? Because at the moment the object in the new iteration is created - i.e. when Python executes the expression to the right side of the = in c = C(), the object of the precvious iteration still exists, referenced by the name c - so the new object is constructed at another memory locaton. Python then proceeds to the assignment of the new object to c at which point the previous object is destroyed as described above - which means that on the next (3rd) iteration, that memory will be available for a new instance of C.

在第二个示例中,新创建的对象从不释放引用,因此它们的内存根本不会释放-新对象始终占据新的内存位置.

On the second example, the newly created objects never loose reference, and therefore their memory is not freed at all - new objects always take up a new memory location.

最重要的是:使用高级语言(例如Python或其他语言)的目的是不必不必担心内存分配.语言会帮您解决这个问题.在这种情况下,正如您所注意到的,CPython(标准)实现恰好正确.在上面的示例中,其他实现(例如Pypy或Jython)在每个实例的内存位置"方面可能具有完全不同的行为,但是从以下各项的观点"来看,所有兼容的实现(包括这3个)都将表现完全相同.Python程序:(1)确实可以访问它一直引用的实例,(2)这些实例的数据无论如何都不会损坏或损坏.

Most important of all: The purpose of using a high level language such as Python or others, is not having to worry about memory allocation. The language takes care of that to you. In this case, the CPython (standard) implementation does just the right thing, as you noticed. Other implementations such as Pypy or Jython can have completely different behavior in regards to the "memory location" of each instances in the above examples, but all conforming implementatons (including these 3) will behave exactly the same from the "point of view" of the Python program: (1) It does have access to the instances it keeps a reference to, (2) the data of these instances is not corrupted or mangled in anyway.

这篇关于python如何在for循环中处理对象实例化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆