Изменение свойства экземпляра класса из файла куда он был импортирован. Асинхронный код
Из названия вы вряд ли что-то поняли, не знаю как это можно сформулировать лучше =). Постараюсь объяснить тут. Весь код максимально упрощён, реальные классы и методы заменены на более простые, большинство ненужного кода убрано, всё для максимального понимания сути. Представим, что есть 2 файла - start.py - запускает весь скрипт и export.py, откуда происходит импорт.
Файл start.py:
# python3.8
import asyncio
# импорт другого файла
import export
class Test:
""" Выдуманный класс """
def __init__(self, arg=0):
# Выдуманный аргумент
self.arg = arg
# функция, которая просто печатает единственный аргумент класса раз в 3 секунды
async def print_arg(self):
while True:
print(self.arg)
await asyncio.sleep(3)
# Создание экземпляра класса
test = Test()
# Функция которая создаёт задачи и запускает их
async def main():
task1 = asyncio.create_task(test.print_arg())
# функция change_class_instance_arg() изменяет arg свойство экземпляра класса
task2 = asyncio.create_task(export.change_class_instance_arg())
await asyncio.gather(task1, task2)
# Не знаю что тут объяснять :D
if __name__ == '__main__':
asyncio.run(main())
Файл export.py:
import asyncio
# импортируем экземпляр класса
from start import test
# Функция, которая раз в 3 секунды прибавляет к свойству arg экземляра класса 1
async def change_class_instance_arg():
while True:
test.arg += 1
await asyncio.sleep(3)
В чём проблема? В консоль печатается всегда 0 и свойство экземпляра класса не изменяется, хотя вторая функция запущена, выполняется и она должна изменять это свойство. Если файлы объединить и поместить эту функцию в первый файл, то всё работает как должно, и каждый вывод в консоль увеличивается на 1.
Почему по-моему мнению это происходит? При импорте создаётся ещё один экземпляр класса и их становится 2. Один создаётся при запуске файла start.py, второй при импорте переменной из файла start.py в export.py
Какие решения мне не подходят?
- Нельзя передавать экземпляр класса в качестве аргумента в функцию
change_class_instance_arg, потому что на месте этой функции находится другая, которая импортируется из библиотеки и я не могу её изменить. Если вам интересно почему функция из библиотеки должна изменять свойства экземпляра моего класса читайте ниже - Не получится сохранять значение в переменные окружения, потому что в реальном коде свойством класса может быть экземпляр другого класса, который никак не сохранить в виде строки
- Объединять файлы. Это очень много кода. Это плохое решение
Почему функция из библиотеки изменяет свойства экземпляра моего класса? Функция из библиотеки это обёртка для моего кода. Внутри этой обёртки находится мой код. (Это не декоратор). Из-за этой обёртки я не могу ничего передать в свою функцию, которая внутри обёртки, потому что эта обёртка ничего не принимает.
Ответы (1 шт):
Происходит примерно следующее
- Модуль
startначинает загружаться под именем__main__, это важно - На строчке
import exportего загрузка приостанавливается до полного исполнения кода модуляexport from start import test(у вас в коде опечатка) приостанавливает загрузку этого модуля, пока не будет загружен модульstartуже под именемstart. То, что он уже загружен (хоть и не выполнен целиком) под именем__main__- не в счет- модуль
startзагружается уже игнорируя импорты, все эти модули уже зарегистрированы - в какой то момент в пространстве имен модуля
startсоздается объектtest - после загрузки кода модуля
start(if __name__ == '__main__'не срабатывает) возвращаемся в модульexport - там связываем имя
testсstart.test, определяем функцию, возрвщаемся к загрузке__main__ - в
__main__помимо прочего создается новый экземплярtest, и запускается asyncio.run()
В результате export.test и start.test - один и тот же объект, а __main__.test - другой. И изменяем мы первый, а печатаем второй
Решение навскидку:
заменить
from start import test
на
import __main__
и
test.arg += 1
на
__main__.test.arg += 1