QML没有获取从PyQt槽接收的对象的所有权

时间:2014-07-03 15:50:56

标签: qt pyqt qml pyqt5

从QML调用Python函数的正确方法是什么,它将实例化并将对象返回给QML,并让QML负责对象的生命周期?我面临的问题是,对象在达到QML之前就会被垃圾收集。

请注意,我不想在Python端保持对对象的显式引用,并且根据the documentation中的以下引用,我所寻找的甚至应该是默认行为:

  

当数据从C ++传输到QML时,数据的所有权   始终使用C ++。 此规则的例外是QObject   从显式C ++方法调用返回:在这种情况下,QML   引擎承担对象的所有权 ...

我创建了一个演示问题的最小可运行示例(gist link):

main.py:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import os
import sys
import signal
from PyQt5.QtGui import QGuiApplication
from PyQt5.QtQuick import QQuickView
from PyQt5.QtCore import QUrl, QObject, QVariant, pyqtSlot
from PyQt5.QtQml import QQmlEngine, qmlRegisterType


class Dummy(QObject):

    def __del__(self):
        print("Deleted")


class GUIEntryPoint(QObject):

    @pyqtSlot(result=QVariant)
    def get_foo(self):
        foo = Dummy()
        print("Created {}".format(foo))
        print("Ownership after instantiation: {}".format(QQmlEngine.objectOwnership(foo)))
        #QQmlEngine.setObjectOwnership(foo, 1)  # has no effect
        return foo

    @pyqtSlot(QVariant)
    def print_foo(self, foo):
        print("{}, ownership: {}".format(foo, QQmlEngine.objectOwnership(foo)))


def run():
    signal.signal(signal.SIGINT, signal.SIG_DFL)

    app = QGuiApplication(sys.argv)

    # these don't seem to make a difference
    qmlRegisterType(GUIEntryPoint, 'GUIEntryPoint', 1, 0, 'GUIEntryPoint')
    qmlRegisterType(Dummy, 'Dummy', 1, 0, 'Dummy')

    qml_url = QUrl.fromLocalFile(os.path.join('zzz.qml'))
    view = QQuickView()

    gep = GUIEntryPoint()
    view.rootContext().setContextProperty('BE', gep)
    view.setSource(qml_url)

    view.show()
    sys.exit(app.exec_())


if __name__ == '__main__':
    run()

zzz.qml:

import QtQuick 2.2


Rectangle {
    id: rootItem
    width: 640
    height: 400

    property var pleaseKeepMe: BE.get_foo()

    Component.onCompleted: {
        console.log("Completed");

        BE.print_foo(pleaseKeepMe);  // prints None, it has been deleted

        console.log("creating another");
        var x = BE.get_foo();
        // at this point x has already been deleted on the Python side
        console.log("created another");
        BE.print_foo(x);  // prints None

        console.log("\n\nPress CTRL-C to exit");
    }
}

1 个答案:

答案 0 :(得分:3)

简而言之:使用SIP Python API将所有权转移到C ++,同时保持Python“活跃于QObject的一部分”似乎解决了问题,这实际上是一个所有权问题,如下所述(另见下文中的评论) :

在SIP API上,请参阅:

另外,一些不错的一般建议是:

问题的一个略微修改的例子,Python源:

from PyQt5.QtGui import QGuiApplication
from PyQt5.QtQuick import QQuickView
from PyQt5.QtCore import QUrl, QObject, QVariant, pyqtSlot
from PyQt5.QtQml import QQmlEngine, qmlRegisterType
import sip

def ownership(obj):
    jsOwned = QQmlEngine.objectOwnership(obj) == QQmlEngine.JavaScriptOwnership
    return "Javascript" if jsOwned else "Cpp"  

def onDummytDestroyed():
    print "Dummy destroyed"

class Dummy(QObject):

    i = 0

    def __init__(self):
        #let's not forget to properly initialize the base part
        super(Dummy, self).__init__()
        self.i = Dummy.i
        Dummy.i = Dummy.i + 1

    def __del__(self):
        #let's track when the Python part gets destroyed 
        #  (or, rather, "finalized", or whatever the correct term is :) )
        print "Dummy.__del__(), self.i:", self.i

    @pyqtSlot(result="QString")
    def get_str(self):
        #let's have a Python (not C++) implemented method in the class
        return "Dummy string #" + str(self.i)

class GUIEntryPoint(QObject):

    def __init__(self):
        #same as with Dummy.__init__
        super(GUIEntryPoint, self).__init__()

    @pyqtSlot(result=QVariant) #would also work
    #@pyqtSlot(result=QObject)
    def get_foo(self):
        print "GUIEntryPoint.get_foo():"
        foo = Dummy()
        foo.setObjectName("Foo")

        #let's track when the C++ part gets destroyed
        foo.destroyed.connect(onDummytDestroyed)

        #this would destroy the Python part of foo as soon as the reference
        #goes out of scope (the C++ part stay alive and will be properly accessible from QML,
        #but attempts to access Python-implemented methods like Dummy.get_str()
        #would cause a TypeError hinting that there is no such method) 
        #sip.transferto(foo, None)

        #this works as expected, with both Python (and then C++) parts of foo
        #being destroyed whenever the QML GC decides to get rid of the object
        #(see program output, notice how GC is silent for a while)  
        sip.transferto(foo, foo)

        #this is indeed not needed, as proper ownership will be set
        #when the object passes to the QML land through the slot invocation
        #QQmlEngine.setObjectOwnership(foo, QQmlEngine.JavaScriptOwnership)
        print "    initial ownership: ", ownership(foo)

        return foo

    @pyqtSlot(QObject) #would also work
    #@pyqtSlot(QVariant) 
    def print_foo(self, foo):
        print "GUIEntryPoint.print_foo():"
        print "    objectName: ", foo.objectName()
        print "    ownership when on QML side: ", ownership(foo)

app = QGuiApplication([])
view = QQuickView()

#not needed, indeed, as both context objects (and properties),
#and QObject descendants passed to QML side are perfectly accessible
#(that is, their properties and invokables / slots are) 
#without any additional steps
#(instantiating types declaratively would require registering them first, though,
#and having properties of custom types requires metatypes to be declared)
#qmlRegisterType(GUIEntryPoint, 'GUIEntryPoint', 1, 0, 'GUIEntryPoint')
#qmlRegisterType(Dummy, 'Dummy', 1, 0, 'Dummy')

gep = GUIEntryPoint()
view.rootContext().setContextProperty('BE', gep)

view.setSource(QUrl.fromLocalFile("pyqt-ownership-test.qml"))
view.show()

app.exec_()

QML来源(另存为pyqt-ownership-test.py):

import QtQuick 2.1

Rectangle {
    width: 300
    height: 200
    color: "red"
    border.width: 10

    Component.onCompleted: {
        console.log("Component.onCompleted():")

        //increase the number to 1000 to see GC stepping in
        //while the loop is still running
        //(notice how destruction is not being reported for some objects,
        //for example, #249 (the one created last),
        //but this looks like a Qt/QML logging issue)
        for (var i = 0; i < 250; i++) {
            console.log("#" + i)
            var foo = BE.get_foo()

            console.log("    foo: " + foo)
            console.log("    foo.objectName: " + foo.objectName)
            console.log("    foo.get_str(): " + foo.get_str())

            console.log("    print_foo():")
            BE.print_foo(foo)
        }
    }
}

程序输出(在中间剥离以适应SO答案大小限制):

Component.onCompleted():
#0
GUIEntryPoint.get_foo():
    initial ownership:  Cpp
    foo: Dummy(0x22903d0, "Foo")
    foo.objectName: Foo
    foo.get_str(): Dummy string #0
    print_foo():
GUIEntryPoint.print_foo():
    objectName:  Foo
    ownership when on QML side:  Javascript
#1
GUIEntryPoint.get_foo():
    initial ownership:  Cpp
    foo: Dummy(0x2290d20, "Foo")
    foo.objectName: Foo
    foo.get_str(): Dummy string #1
    print_foo():
GUIEntryPoint.print_foo():
    objectName:  Foo
    ownership when on QML side:  Javascript
#2
GUIEntryPoint.get_foo():
    initial ownership:  Cpp
    foo: Dummy(0x2291080, "Foo")
    foo.objectName: Foo
    foo.get_str(): Dummy string #2
    print_foo():
GUIEntryPoint.print_foo():
    objectName:  Foo
    ownership when on QML side:  Javascript
#3
GUIEntryPoint.get_foo():
    initial ownership:  Cpp
    foo: Dummy(0x22911e0, "Foo")
    foo.objectName: Foo
    foo.get_str(): Dummy string #3
    print_foo():
GUIEntryPoint.print_foo():
    objectName:  Foo
    ownership when on QML side:  Javascript
#4
GUIEntryPoint.get_foo():
    initial ownership:  Cpp
    foo: Dummy(0x2291e90, "Foo")
    foo.objectName: Foo
    foo.get_str(): Dummy string #4
    print_foo():
GUIEntryPoint.print_foo():
    objectName:  Foo
    ownership when on QML side:  Javascript
#5
GUIEntryPoint.get_foo():
    initial ownership:  Cpp
    foo: Dummy(0x2292b70, "Foo")
    foo.objectName: Foo
    foo.get_str(): Dummy string #5
    print_foo():
GUIEntryPoint.print_foo():
    objectName:  Foo
    ownership when on QML side:  Javascript
#6
GUIEntryPoint.get_foo():
    initial ownership:  Cpp
    foo: Dummy(0x2293420, "Foo")
    foo.objectName: Foo
    foo.get_str(): Dummy string #6
    print_foo():
GUIEntryPoint.print_foo():
    objectName:  Foo
    ownership when on QML side:  Javascript
#7
GUIEntryPoint.get_foo():
    initial ownership:  Cpp
    foo: Dummy(0x2296e30, "Foo")
    foo.objectName: Foo
    foo.get_str(): Dummy string #7
    print_foo():
GUIEntryPoint.print_foo():
    objectName:  Foo
    ownership when on QML side:  Javascript
#8
GUIEntryPoint.get_foo():
    initial ownership:  Cpp
    foo: Dummy(0x22983b0, "Foo")
    foo.objectName: Foo
    foo.get_str(): Dummy string #8
    print_foo():
GUIEntryPoint.print_foo():
    objectName:  Foo
    ownership when on QML side:  Javascript
#9
GUIEntryPoint.get_foo():
    initial ownership:  Cpp
    foo: Dummy(0x2299150, "Foo")
    foo.objectName: Foo
    foo.get_str(): Dummy string #9
    print_foo():
GUIEntryPoint.print_foo():
    objectName:  Foo
    ownership when on QML side:  Javascript
#10
GUIEntryPoint.get_foo():
    initial ownership:  Cpp
    foo: Dummy(0x2299e60, "Foo")
    foo.objectName: Foo
    foo.get_str(): Dummy string #10
    print_foo():
GUIEntryPoint.print_foo():
    objectName:  Foo
    ownership when on QML side:  Javascript
#11
GUIEntryPoint.get_foo():
    initial ownership:  Cpp
    foo: Dummy(0x229ab70, "Foo")
    foo.objectName: Foo
    foo.get_str(): Dummy string #11
    print_foo():
GUIEntryPoint.print_foo():
    objectName:  Foo
    ownership when on QML side:  Javascript

<...some lines skipped here...>

#245
GUIEntryPoint.get_foo():
    initial ownership:  Cpp
    foo: Dummy(0x23007b0, "Foo")
    foo.objectName: Foo
    foo.get_str(): Dummy string #245
    print_foo():
GUIEntryPoint.print_foo():
    objectName:  Foo
    ownership when on QML side:  Javascript
#246
GUIEntryPoint.get_foo():
    initial ownership:  Cpp
    foo: Dummy(0x22fe4d0, "Foo")
    foo.objectName: Foo
    foo.get_str(): Dummy string #246
    print_foo():
GUIEntryPoint.print_foo():
    objectName:  Foo
    ownership when on QML side:  Javascript
#247
GUIEntryPoint.get_foo():
    initial ownership:  Cpp
    foo: Dummy(0x22fc5c0, "Foo")
    foo.objectName: Foo
    foo.get_str(): Dummy string #247
    print_foo():
GUIEntryPoint.print_foo():
    objectName:  Foo
    ownership when on QML side:  Javascript
#248
GUIEntryPoint.get_foo():
    initial ownership:  Cpp
    foo: Dummy(0x22fa730, "Foo")
    foo.objectName: Foo
    foo.get_str(): Dummy string #248
    print_foo():
GUIEntryPoint.print_foo():
    objectName:  Foo
    ownership when on QML side:  Javascript
#249
GUIEntryPoint.get_foo():
    initial ownership:  Cpp
    foo: Dummy(0x22f57b0, "Foo")
    foo.objectName: Foo
    foo.get_str(): Dummy string #249
    print_foo():
GUIEntryPoint.print_foo():
    objectName:  Foo
    ownership when on QML side:  Javascript
Dummy.__del__(), self.i: 214
Dummy destroyed
Dummy.__del__(), self.i: 213
Dummy destroyed
Dummy.__del__(), self.i: 212
Dummy destroyed
Dummy.__del__(), self.i: 211
Dummy destroyed
Dummy.__del__(), self.i: 210
Dummy destroyed
Dummy.__del__(), self.i: 209
Dummy destroyed
Dummy.__del__(), self.i: 208
Dummy destroyed
Dummy.__del__(), self.i: 207
Dummy destroyed
Dummy.__del__(), self.i: 206
Dummy destroyed
Dummy.__del__(), self.i: 205
Dummy destroyed
Dummy.__del__(), self.i: 204
Dummy destroyed
Dummy.__del__(), self.i: 203
Dummy destroyed
Dummy.__del__(), self.i: 202
Dummy destroyed
Dummy.__del__(), self.i: 201
Dummy destroyed
Dummy.__del__(), self.i: 200
Dummy destroyed
Dummy.__del__(), self.i: 199
Dummy destroyed
Dummy.__del__(), self.i: 198
Dummy destroyed
Dummy.__del__(), self.i: 197
Dummy destroyed
Dummy.__del__(), self.i: 196
Dummy destroyed
Dummy.__del__(), self.i: 195
Dummy destroyed
Dummy.__del__(), self.i: 194
Dummy destroyed
Dummy.__del__(), self.i: 193
Dummy destroyed
Dummy.__del__(), self.i: 192
Dummy destroyed
Dummy.__del__(), self.i: 191
Dummy destroyed
Dummy.__del__(), self.i: 190
Dummy destroyed
Dummy.__del__(), self.i: 189
Dummy destroyed
Dummy.__del__(), self.i: 188
Dummy destroyed
Dummy.__del__(), self.i: 187
Dummy destroyed
Dummy.__del__(), self.i: 186
Dummy destroyed
Dummy.__del__(), self.i: 185
Dummy destroyed
Dummy.__del__(), self.i: 184
Dummy destroyed
Dummy.__del__(), self.i: 183
Dummy destroyed
Dummy.__del__(), self.i: 182
Dummy destroyed
Dummy.__del__(), self.i: 181
Dummy destroyed
Dummy.__del__(), self.i: 180
Dummy destroyed
Dummy.__del__(), self.i: 179
Dummy destroyed
Dummy.__del__(), self.i: 178
Dummy destroyed
Dummy.__del__(), self.i: 177
Dummy destroyed
Dummy.__del__(), self.i: 176
Dummy destroyed
Dummy.__del__(), self.i: 175
Dummy destroyed
Dummy.__del__(), self.i: 174
Dummy destroyed
Dummy.__del__(), self.i: 173
Dummy destroyed
Dummy.__del__(), self.i: 172
Dummy destroyed
Dummy.__del__(), self.i: 171
Dummy destroyed
Dummy.__del__(), self.i: 170
Dummy destroyed
Dummy.__del__(), self.i: 169
Dummy destroyed
Dummy.__del__(), self.i: 168
Dummy destroyed
Dummy.__del__(), self.i: 167
Dummy destroyed
Dummy.__del__(), self.i: 166
Dummy destroyed
Dummy.__del__(), self.i: 165
Dummy destroyed
Dummy.__del__(), self.i: 164
Dummy destroyed
Dummy.__del__(), self.i: 163
Dummy destroyed
Dummy.__del__(), self.i: 162
Dummy destroyed
Dummy.__del__(), self.i: 161
Dummy destroyed
Dummy.__del__(), self.i: 160
Dummy destroyed
Dummy.__del__(), self.i: 159
Dummy destroyed
Dummy.__del__(), self.i: 158
Dummy destroyed
Dummy.__del__(), self.i: 157
Dummy destroyed
Dummy.__del__(), self.i: 156
Dummy destroyed
Dummy.__del__(), self.i: 155
Dummy destroyed
Dummy.__del__(), self.i: 154
Dummy destroyed
Dummy.__del__(), self.i: 153
Dummy destroyed
Dummy.__del__(), self.i: 152
Dummy destroyed
Dummy.__del__(), self.i: 151
Dummy destroyed
Dummy.__del__(), self.i: 150
Dummy destroyed
Dummy.__del__(), self.i: 149
Dummy destroyed
Dummy.__del__(), self.i: 148
Dummy destroyed
Dummy.__del__(), self.i: 147
Dummy destroyed
Dummy.__del__(), self.i: 146
Dummy destroyed
Dummy.__del__(), self.i: 145
Dummy destroyed
Dummy.__del__(), self.i: 144
Dummy destroyed
Dummy.__del__(), self.i: 143
Dummy destroyed
Dummy.__del__(), self.i: 142
Dummy destroyed
Dummy.__del__(), self.i: 141
Dummy destroyed
Dummy.__del__(), self.i: 140
Dummy destroyed
Dummy.__del__(), self.i: 139
Dummy destroyed
Dummy.__del__(), self.i: 138
Dummy destroyed
Dummy.__del__(), self.i: 137
Dummy destroyed
Dummy.__del__(), self.i: 136
Dummy destroyed
Dummy.__del__(), self.i: 135
Dummy destroyed
Dummy.__del__(), self.i: 134
Dummy destroyed
Dummy.__del__(), self.i: 133
Dummy destroyed
Dummy.__del__(), self.i: 132
Dummy destroyed
Dummy.__del__(), self.i: 131
Dummy destroyed
Dummy.__del__(), self.i: 130
Dummy destroyed
Dummy.__del__(), self.i: 129
Dummy destroyed
Dummy.__del__(), self.i: 128
Dummy destroyed
Dummy.__del__(), self.i: 127
Dummy destroyed
Dummy.__del__(), self.i: 126
Dummy destroyed
Dummy.__del__(), self.i: 125
Dummy destroyed
Dummy.__del__(), self.i: 124
Dummy destroyed
Dummy.__del__(), self.i: 123
Dummy destroyed
Dummy.__del__(), self.i: 122
Dummy destroyed
Dummy.__del__(), self.i: 121
Dummy destroyed
Dummy.__del__(), self.i: 120
Dummy destroyed
Dummy.__del__(), self.i: 119
Dummy destroyed
Dummy.__del__(), self.i: 118
Dummy destroyed
Dummy.__del__(), self.i: 117
Dummy destroyed
Dummy.__del__(), self.i: 116
Dummy destroyed
Dummy.__del__(), self.i: 115
Dummy destroyed
Dummy.__del__(), self.i: 114
Dummy destroyed
Dummy.__del__(), self.i: 113
Dummy destroyed
Dummy.__del__(), self.i: 112
Dummy destroyed
Dummy.__del__(), self.i: 111
Dummy destroyed
Dummy.__del__(), self.i: 110
Dummy destroyed
Dummy.__del__(), self.i: 109
Dummy destroyed
Dummy.__del__(), self.i: 108
Dummy destroyed
Dummy.__del__(), self.i: 107
Dummy destroyed
Dummy.__del__(), self.i: 106
Dummy destroyed
Dummy.__del__(), self.i: 105
Dummy destroyed
Dummy.__del__(), self.i: 104
Dummy destroyed
Dummy.__del__(), self.i: 103
Dummy destroyed
Dummy.__del__(), self.i: 102
Dummy destroyed
Dummy.__del__(), self.i: 101
Dummy destroyed
Dummy.__del__(), self.i: 100
Dummy destroyed
Dummy.__del__(), self.i: 99
Dummy destroyed
Dummy.__del__(), self.i: 98
Dummy destroyed
Dummy.__del__(), self.i: 97
Dummy destroyed
Dummy.__del__(), self.i: 96
Dummy destroyed
Dummy.__del__(), self.i: 95
Dummy destroyed
Dummy.__del__(), self.i: 94
Dummy destroyed
Dummy.__del__(), self.i: 93
Dummy destroyed
Dummy.__del__(), self.i: 92
Dummy destroyed
Dummy.__del__(), self.i: 91
Dummy destroyed
Dummy.__del__(), self.i: 90
Dummy destroyed
Dummy.__del__(), self.i: 89
Dummy destroyed
Dummy.__del__(), self.i: 88
Dummy destroyed
Dummy.__del__(), self.i: 87
Dummy destroyed
Dummy.__del__(), self.i: 86
Dummy destroyed
Dummy.__del__(), self.i: 85
Dummy destroyed
Dummy.__del__(), self.i: 84
Dummy destroyed
Dummy.__del__(), self.i: 83
Dummy destroyed
Dummy.__del__(), self.i: 82
Dummy destroyed
Dummy.__del__(), self.i: 81
Dummy destroyed
Dummy.__del__(), self.i: 80
Dummy destroyed
Dummy.__del__(), self.i: 79
Dummy destroyed
Dummy.__del__(), self.i: 78
Dummy destroyed
Dummy.__del__(), self.i: 77
Dummy destroyed
Dummy.__del__(), self.i: 76
Dummy destroyed
Dummy.__del__(), self.i: 75
Dummy destroyed
Dummy.__del__(), self.i: 74
Dummy destroyed
Dummy.__del__(), self.i: 73
Dummy destroyed
Dummy.__del__(), self.i: 72
Dummy destroyed
Dummy.__del__(), self.i: 71
Dummy destroyed
Dummy.__del__(), self.i: 70
Dummy destroyed
Dummy.__del__(), self.i: 69
Dummy destroyed
Dummy.__del__(), self.i: 68
Dummy destroyed
Dummy.__del__(), self.i: 67
Dummy destroyed
Dummy.__del__(), self.i: 66
Dummy destroyed
Dummy.__del__(), self.i: 65
Dummy destroyed
Dummy.__del__(), self.i: 64
Dummy destroyed
Dummy.__del__(), self.i: 63
Dummy destroyed
Dummy.__del__(), self.i: 62
Dummy destroyed
Dummy.__del__(), self.i: 61
Dummy destroyed
Dummy.__del__(), self.i: 60
Dummy destroyed
Dummy.__del__(), self.i: 59
Dummy destroyed
Dummy.__del__(), self.i: 58
Dummy destroyed
Dummy.__del__(), self.i: 57
Dummy destroyed
Dummy.__del__(), self.i: 56
Dummy destroyed
Dummy.__del__(), self.i: 55
Dummy destroyed
Dummy.__del__(), self.i: 54
Dummy destroyed
Dummy.__del__(), self.i: 53
Dummy destroyed
Dummy.__del__(), self.i: 52
Dummy destroyed
Dummy.__del__(), self.i: 51
Dummy destroyed
Dummy.__del__(), self.i: 50
Dummy destroyed
Dummy.__del__(), self.i: 49
Dummy destroyed
Dummy.__del__(), self.i: 48
Dummy destroyed
Dummy.__del__(), self.i: 47
Dummy destroyed
Dummy.__del__(), self.i: 46
Dummy destroyed
Dummy.__del__(), self.i: 45
Dummy destroyed
Dummy.__del__(), self.i: 44
Dummy destroyed
Dummy.__del__(), self.i: 43
Dummy destroyed
Dummy.__del__(), self.i: 42
Dummy destroyed
Dummy.__del__(), self.i: 41
Dummy destroyed
Dummy.__del__(), self.i: 40
Dummy destroyed
Dummy.__del__(), self.i: 39
Dummy destroyed
Dummy.__del__(), self.i: 38
Dummy destroyed
Dummy.__del__(), self.i: 37
Dummy destroyed
Dummy.__del__(), self.i: 36
Dummy destroyed
Dummy.__del__(), self.i: 35
Dummy destroyed
Dummy.__del__(), self.i: 34
Dummy destroyed
Dummy.__del__(), self.i: 33
Dummy destroyed
Dummy.__del__(), self.i: 32
Dummy destroyed
Dummy.__del__(), self.i: 31
Dummy destroyed
Dummy.__del__(), self.i: 30
Dummy destroyed
Dummy.__del__(), self.i: 29
Dummy destroyed
Dummy.__del__(), self.i: 28
Dummy destroyed
Dummy.__del__(), self.i: 27
Dummy destroyed
Dummy.__del__(), self.i: 26
Dummy destroyed
Dummy.__del__(), self.i: 25
Dummy destroyed
Dummy.__del__(), self.i: 24
Dummy destroyed
Dummy.__del__(), self.i: 23
Dummy destroyed
Dummy.__del__(), self.i: 22
Dummy destroyed
Dummy.__del__(), self.i: 21
Dummy destroyed
Dummy.__del__(), self.i: 20
Dummy destroyed
Dummy.__del__(), self.i: 19
Dummy destroyed
Dummy.__del__(), self.i: 18
Dummy destroyed
Dummy.__del__(), self.i: 17
Dummy destroyed
Dummy.__del__(), self.i: 16
Dummy destroyed
Dummy.__del__(), self.i: 15
Dummy destroyed
Dummy.__del__(), self.i: 14
Dummy destroyed
Dummy.__del__(), self.i: 13
Dummy destroyed
Dummy.__del__(), self.i: 12
Dummy destroyed
Dummy.__del__(), self.i: 11
Dummy destroyed
Dummy.__del__(), self.i: 10
Dummy destroyed
Dummy.__del__(), self.i: 9
Dummy destroyed
Dummy.__del__(), self.i: 8
Dummy destroyed
Dummy.__del__(), self.i: 7
Dummy destroyed
Dummy.__del__(), self.i: 6
Dummy destroyed
Dummy.__del__(), self.i: 5
Dummy destroyed
Dummy.__del__(), self.i: 4
Dummy destroyed
Dummy.__del__(), self.i: 3
Dummy destroyed
Dummy.__del__(), self.i: 2
Dummy destroyed
Dummy.__del__(), self.i: 1
Dummy destroyed
Dummy.__del__(), self.i: 0
Dummy destroyed