Форум сайта python.su
0
Добрый вечер. Интересно, как обстоят дела с предсказуемостью вызова __del__ в однопоточном скрипте без каллбеков (ну в смысле, запускается, считает, и выключается).
Я так понимаю, что объект попадает в сборщик сразу как исчезает его референс (локальная переменная).
Вот такой тест у меня стабильно в разных вариантах выдает одинаковую логику вызова метода __del__:
class Return: count = 0 def __init__(self): Return.count += 1 self.count = Return.count print(f'{self} init') def __str__(self): return f'Return object {self.count}' def __del__(self): print(f'{self} delete') def foo(): print('inside foo') return Return() def test(): print('inside test') print('calling foo to x') x = foo() print('x is ', x) print('calling foo to print:', foo(), sep='\n') print('test end') return print('start') test() print('end')
start
inside test
calling foo to x
inside foo
Return object 1 init
x is Return object 1
inside foo
Return object 2 init
calling foo to print:
Return object 2
Return object 2 delete
test end
Return object 1 delete
end
[Finished in 0.2s]
Офлайн
0
чуть модифицированная версия:
class Return: count = 0 def __init__(self): Return.count += 1 self.count = Return.count print(f'{self} init') def __str__(self): return f'Return object {self.count}' def __del__(self): print(f'{self} delete') def foo(): print('inside foo') return Return() def test(): print('inside test') print('calling foo to x') x = foo() print('x is ', x) print('calling foo to print:', foo(), sep='\n') print('test end') return x print('start') print('calling test to module_x') module_x = test() print('module_x is ', module_x) print('\ncalling test to nowhere') test() print('deleting module_x') del(module_x) print('end')
start
calling test to module_x
inside test
calling foo to x
inside foo
Return object 1 init
x is Return object 1
inside foo
Return object 2 init
calling foo to print:
Return object 2
Return object 2 delete
test end
module_x is Return object 1
calling test to nowhere
inside test
calling foo to x
inside foo
Return object 3 init
x is Return object 3
inside foo
Return object 4 init
calling foo to print:
Return object 4
Return object 4 delete
test end
Return object 3 delete
deleting module_x
Return object 1 delete
end
[Finished in 0.1s]
Офлайн
253
LevitanusСовсем нельзя полагаться. Вот если в спецификации языка будет написано тогда можно будет полагаться.
насколько можно полагаться на такое поведение?
Офлайн
0
спасибо
Офлайн
294
LevitanusЭто не совсем так, у каждого обьекта есть счетчик, который хранит количество ссылок на объект. Когда “ исчезает его референс ” счетчик становиться меньше на единицу. Метод же будет вызван, только когда счётчик ссылок достигнет нуля.
Я так понимаю, что объект попадает в сборщик сразу как исчезает его референс (локальная переменная).
[code python][/code]
Офлайн
0
Можно тогда здесь же спрошу? Чего-то не могу придумать:
(пакет - API для генерации кода на более примитивном языке. По сути, классы пакета транслируются в исходники другого ЯП, а вокруг “препроцессор” уже пишется на нормальном питоне.)
У меня функция в декораторе может возвращать объект из самопального стека (в силу специфики задачи, стек должен быть простым как пробка).
В момент вызова функции создается новый фрейм, в который спихиваются все локали и return, если есть.
В момент выхода, по идее, надо либо держать фрейм до тех пор, пока на него есть референс (что я и хотел сделать через __del__), либо делать pop() прямо в декораторе (по сути, там просто счетчик указателя на ячейку массива стартовых элементов фреймов откатывается на1).
Так вот во втором случае, если использовать объект стека сам по себе, а не класть его значение внутрь “глобальных” классов, можно столкнуться с тем, что в стек уже на место даты искомого объекта что-то попало.
Как бы так запретить его использовать где либо, кроме инстанций “глобальных классов”.
Я вот читаю, и понимаю, что звучит как жопа в архитектуре. Но решать задачу статическим анализом очень не хочу. Может я не прав, но мне кажется, не тот случай, и изначальная идея - использовать чистый исполняемый питон.
Офлайн
0
ок, решил упростить задачу через дополнительный аргумент out и проверкой на возвращение None
Офлайн