Второе обновление :
Хорошо, мы знаем, что основная проблема в том, что python уничтожает Bar
немедленно. Когда Bar
реализован в python, gc python знает, что есть ссылка на theFoo
, и поэтому не уничтожает его. Но когда Bar
реализован в C ++, Python вызывает деструктор C ++, который автоматически уничтожает theFoo
вместе с Bar.
Таким образом, очевидное решение состоит в том, чтобы предотвратить преждевременное уничтожение Python Bar
. Вот немного хакерское решение, включающее подклассы Bar
:
class PersistentBar(swigexample.Bar):
lastpbar = None
def __init__(self):
super(PersistentBar, self).__init__()
PersistentBar.lastpbar = self
Сохраняет ссылку на последний Bar
, созданный таким образом, что он не будет сразу уничтожен. Когда создается новый Bar
, старый удаляется. (Моя старая версия была глупой; для этого не нужно переопределять __del__
.) Вот вывод (с cout << "deleting Foo "
в деструкторе Foo
):
>>> from test import persistentBar
>>> persistentBar().theFoo.value
1
>>> persistentBar().theFoo.value
deleting Foo 1
>>> persistentBar().theFoo.value
deleting Foo 1
Я все еще не люблю это. Может быть лучше изолировать «постоянное» поведение в декораторе; Я тоже попробовал, и это сработало (если вы хотите увидеть код, дайте мне знать). Определенно лучше было бы как-то сказать python, что он должен обрабатывать уничтожение theFoo
, но я не могу понять, как это сделать.
Первое обновление :
Код переноса мне ничего не сказал, поэтому я посмотрел в swigexample.py. Это также ничего не дало. Ситуация прояснилась, когда я попытался продублировать Bar
на чистом питоне:
# pyfoobar.py
class Foo(object):
def __init__(self):
self.value = -1
class Bar(object):
def __init__(self):
self.theFoo = Foo()
self.theFoo.value = 1
def __del__(self):
self.theFoo.value = 0
Теперь мы импортируем Bar из pyfoobar:
>>> from pyfoobar import Bar
>>> b = Bar()
>>> b.theFoo.value
1
>>> Bar().theFoo.value
0
Такое поведение исходит от Python!
Оригинальный ответ :
Похоже, что здесь определенно происходит какое-то сражение по сбору мусора ... Вот некоторая связанная информация по SWIG Memory Management . Исходя из этого, похоже, что директива% newobject может быть тем, что вы ищете; но я попробовал несколько вариантов и не смог заставить его контролировать Python над theFoo
:
>>> from swigexample import Bar
>>> b = Bar()
>>> b.theFoo.value
1
>>> b.theFoo.thisown
False
>>> Bar().theFoo.value
0
>>> Bar().theFoo.thisown
False
Я начинаю подозревать, что это намеренно; Похоже, эта строка из приведенной выше ссылки актуальна здесь:
C теперь содержит ссылку на
объект --- вы, вероятно, не хотите
Питон, чтобы уничтожить его.
Но я не уверен. Я собираюсь посмотреть на код swigexample_wrap, чтобы узнать, смогу ли я выяснить, когда вызывается ~Bar
.