Класс в реальном приложении отвечает за создание нового средства записи журнала (по сути, оболочки файлового потока) и регистрацию некоторых его методов (которые внутренне используют член записи файла) в качестве обратных вызовов для обработки связи MQTT.
У модуля записи файлов есть финализатор, который закрывает файл, у основного класса есть финализатор, который отменяет регистрацию обратных вызовов (он также отключается от клиента paho MQTT и отписывается от тем, но это не имеет значения).
Я понимаю, что финализатор средства записи журнала не может быть вызван до тех пор, пока не будет вызван финализатор основного класса, поскольку методы, зарегистрированные как обратные вызовы, все еще ссылаются на средство записи журнала. Чего я не понимаю, так это почему финализаторы вообще не вызываются.
Я попытался воспроизвести проблему на фиктивном примере. Здесь CallbackContainer — это просто способ сохранить вызываемый объект за пределами основного класса Supervisor.
import os
from weakref import finalize
from collections.abc import Callable
from typing import Optional
class FileStreamWrapper:
def __init__(self, file: str):
if os.path.isfile(file):
os.remove(file)
file_stream = open(file, "w")
def finalizer():
file_stream.close()
print("finalized 'FileStreamWrapper' object")
finalize(self, finalizer)
self._file_stream = file_stream
def print_line(self, line: str):
self._file_stream.write(line + "\n")
class CallbackContainer:
def __init__(self):
self._callback: Optional[Callable[[], None]] = None
def register_callback(self, callback: Callable[[], None]):
self._callback = callback
def unregister_callback(self):
self._callback = None
class Supervisor:
def __init__(self) -> None:
file_stream_wrapper = FileStreamWrapper("test.txt")
callback_container = CallbackContainer()
callback_container.register_callback(lambda : self._print_line(""))
def finalizer():
callback_container.unregister_callback()
print("finalized 'Supervisor' object")
finalize(self, finalizer)
self._file_stream_wrapper = file_stream_wrapper
self._callback_container = callback_container
def _print_line(self, line: str):
self._file_stream_wrapper.print_line(line)
if __name__ == '__main__':
for _ in range(2):
supervisor = Supervisor()
del supervisor
Я ожидал, что оба финализатора будут выполняться в конце каждой итерации после удаления супервизора. Напротив, поскольку файл не закрыт, при создании второго экземпляра Supervisor возникает исключение PermissionError, вынуждающее интерпретатор завершить работу, что приводит к окончательному выполнению предыдущих финализаторов.
PermissionError: [WinError 32] The process cannot access the file because it is being used by another process: 'test.txt'
finalized 'FileStreamWrapper' object
finalized 'Supervisor' object
Подробнее здесь: https://stackoverflow.com/questions/792 ... e-collecte
Регистрация метода в качестве обратного вызова предотвращает сбор мусора для объекта, даже если предоставляется финализа ⇐ Python
Программы на Python
1734207208
Anonymous
Класс в реальном приложении отвечает за создание нового средства записи журнала (по сути, оболочки файлового потока) и регистрацию некоторых его методов (которые внутренне используют член записи файла) в качестве обратных вызовов для обработки связи MQTT.
У модуля записи файлов есть финализатор, который закрывает файл, у основного класса есть финализатор, который отменяет регистрацию обратных вызовов (он также отключается от клиента paho MQTT и отписывается от тем, но это не имеет значения).
Я понимаю, что финализатор средства записи журнала не может быть вызван до тех пор, пока не будет вызван финализатор основного класса, поскольку методы, зарегистрированные как обратные вызовы, все еще ссылаются на средство записи журнала. Чего я не понимаю, так это почему финализаторы вообще не вызываются.
Я попытался воспроизвести проблему на фиктивном примере. Здесь CallbackContainer — это просто способ сохранить вызываемый объект за пределами основного класса Supervisor.
import os
from weakref import finalize
from collections.abc import Callable
from typing import Optional
class FileStreamWrapper:
def __init__(self, file: str):
if os.path.isfile(file):
os.remove(file)
file_stream = open(file, "w")
def finalizer():
file_stream.close()
print("finalized 'FileStreamWrapper' object")
finalize(self, finalizer)
self._file_stream = file_stream
def print_line(self, line: str):
self._file_stream.write(line + "\n")
class CallbackContainer:
def __init__(self):
self._callback: Optional[Callable[[], None]] = None
def register_callback(self, callback: Callable[[], None]):
self._callback = callback
def unregister_callback(self):
self._callback = None
class Supervisor:
def __init__(self) -> None:
file_stream_wrapper = FileStreamWrapper("test.txt")
callback_container = CallbackContainer()
callback_container.register_callback(lambda : self._print_line(""))
def finalizer():
callback_container.unregister_callback()
print("finalized 'Supervisor' object")
finalize(self, finalizer)
self._file_stream_wrapper = file_stream_wrapper
self._callback_container = callback_container
def _print_line(self, line: str):
self._file_stream_wrapper.print_line(line)
if __name__ == '__main__':
for _ in range(2):
supervisor = Supervisor()
del supervisor
Я ожидал, что оба финализатора будут выполняться в конце каждой итерации после удаления супервизора. Напротив, поскольку файл не закрыт, при создании второго экземпляра Supervisor возникает исключение PermissionError, вынуждающее интерпретатор завершить работу, что приводит к окончательному выполнению предыдущих финализаторов.
PermissionError: [WinError 32] The process cannot access the file because it is being used by another process: 'test.txt'
finalized 'FileStreamWrapper' object
finalized 'Supervisor' object
Подробнее здесь: [url]https://stackoverflow.com/questions/79281335/registering-a-method-as-callback-prevents-the-object-from-being-garbage-collecte[/url]
Ответить
1 сообщение
• Страница 1 из 1
Перейти
- Кемерово-IT
- ↳ Javascript
- ↳ C#
- ↳ JAVA
- ↳ Elasticsearch aggregation
- ↳ Python
- ↳ Php
- ↳ Android
- ↳ Html
- ↳ Jquery
- ↳ C++
- ↳ IOS
- ↳ CSS
- ↳ Excel
- ↳ Linux
- ↳ Apache
- ↳ MySql
- Детский мир
- Для души
- ↳ Музыкальные инструменты даром
- ↳ Печатная продукция даром
- Внешняя красота и здоровье
- ↳ Одежда и обувь для взрослых даром
- ↳ Товары для здоровья
- ↳ Физкультура и спорт
- Техника - даром!
- ↳ Автомобилистам
- ↳ Компьютерная техника
- ↳ Плиты: газовые и электрические
- ↳ Холодильники
- ↳ Стиральные машины
- ↳ Телевизоры
- ↳ Телефоны, смартфоны, плашеты
- ↳ Швейные машинки
- ↳ Прочая электроника и техника
- ↳ Фототехника
- Ремонт и интерьер
- ↳ Стройматериалы, инструмент
- ↳ Мебель и предметы интерьера даром
- ↳ Cантехника
- Другие темы
- ↳ Разное даром
- ↳ Давай меняться!
- ↳ Отдам\возьму за копеечку
- ↳ Работа и подработка в Кемерове
- ↳ Давай с тобой поговорим...
Мобильная версия