Модуль перезагружается и сбрасывается без явной инструкции - PullRequest
2 голосов
/ 12 марта 2020

TLDR: я хочу знать в общих чертах, что может привести к перезагрузке модуля и его возврату в исходное состояние без явной попытки его получить.

Я пришел к выводу, что мой основной модуль перезагружается и в процессе все переменные повторно инициализируются в их начальное состояние.

Я не могу привести минимальный воспроизводимый пример. После поиска в Google я не могу найти ничего другого на эту тему, кроме того, что python3 .x не должен перезагружать модули, если это явно не указано.

Использование pygame 1.9.6.

Я хочу спросить, что обычно вызывает такое поведение. Пример моего основного модуля с моими добавленными отладочными отпечатками:

import pygame
from sys import exit

class Engine:
    def __init__(self):
        self.init = False
        self.running = False

    def start(self):
        print("engine start called")
        print("self.init state:", self.init)        

        from graphics import render
        render.init()

        from initializer import initializer
        initializer.init_sprites()

        if not self.init:
            self.init = True
            self.running = True

        print("new self.init state:", self.init)

        self.main_loop()

    def update_input(self):
        pass

    def update_events(self):
        pass

    def update_graphics(self):
        pass

    def self.main_loop() # it's at the very end of the real Engine() aswell
        while True:
            self.update_input()
            self.update_events()
            self.update_graphics()

        pygame.quit()
        exit()


engine = Engine()

print("above engine start reached")

app_init = False # I added this purely for debugging reasons

if not app_init:
    app_init = True
    engine.start()

Приложение не аварийно завершает работу или выдает исключения, потому что все остальные модули продолжают работать так, как должны. Например, спрайты сохраняют свои состояния и продолжают двигаться как следует. Камера по-прежнему прокручивается и т. Д. c.

Однако консоль выдает:

above engine.start() reached
engine start called
self.init state: False
render.init called
new self.init state: True
#stuff happening in background in other modules, no methods changing self.running or explicitly reloading main module. However imports of engine object do happen
above engine.start() reached
engine start called
self.init state: False
render.init called
new self.init state: True

НО:

1) main_l oop () никогда не возвращается к

2) Отпечатки доказывает, что конец основного модуля каким-то образом достигнут, хотя должен быть активным параметр While l oop, и приложение должно завершить работу (), если оно проходит мимо l oop в main_l oop ()

3) Состояние self.init и глобальное app_init сбрасывается в жестко запрограммированное значение, и engine.start () вызывается так, как если бы модуль был инициализирован впервые

Это проблема импорта?

Обновление:

Не решено. Но я удалил все побочные эффекты, не давая всем другим модулям быть повторно инициализированными. Однако это выглядит как грязный взлом, и я боюсь, что перезагрузка моего основного модуля рано или поздно приведет к последствиям.

1 Ответ

2 голосов
/ 12 марта 2020

Это в основном дикое предположение, но единственное объяснение, которое я могу представить с предоставленной информацией, - это то, что некоторые из ваших "других модулей" импортируют ваш файл. Если это так, вы должны реструктурировать свой код, чтобы избежать циклических зависимостей. Простой способ проверить это состоит в том, чтобы добавить защиту, предотвращающую выполнение всего под вашим определением класса при импорте:

class Engine:
    # ...


if __name__ == "__main__":

    engine = Engine()

    print("above engine start reached")

    app_init = False # I added this purely for debugging reasons

    if not app_init:
        app_init = True
        engine.start()

Также, пожалуйста, переместите ваши импорты (те, что в Engine.__init__) вверху модуля. -уровень.

РЕДАКТИРОВАТЬ :

Проблема с импортом (я получил deltatime из движка в другом модуле).

Проблема дизайна.

После удаления этого импорта движок больше не инициализируется повторно. Я сейчас использую, если name == "main". (...) Я понятия не имел, что engine = Engine () внизу будет повторно инициализировать engine при импорте модуля.

Python - язык времени выполнения - за исключением байт-кода компиляция, все происходит во время выполнения. Когда модуль Python загружается впервые (в данном процессе), выполняется весь код на верхнем уровне модуля - так создаются функции и классы (def и class являются исполняемыми операторами ) et c - тогда он кешируется в sys.modules dict (под именем модуля) для других импортов (поэтому он загружается только один раз).

Теперь, когда модуль используется в качестве сценария, происходит то же самое, за исключением того, что модуль импортируется (и кэшируется) под именем __main__. Поэтому, когда ваш другой модуль пытается импортировать ваш основной скрипт, загрузчик ищет имя скрипта, не находит его (потому что он был кэширован как « main », а не как «youscriptname»), и так перезагружает это. Это объясняет двойную загрузку, но это также означает, что эти два модуля - это разные экземпляры, классы - это разные классы, а экземпляры 'engine' - это разные экземпляры.

IOW, в то время как защита if __name__ == '__main__' предотвращает повторное выполнение "основного" кода вашего скрипта, вы только замаскировали симптом, но не устранили проблему root. Короче говоря, ни один из ваших модулей не должен пытаться получить доступ к чему-либо определенному в основном скрипте.

Если в вашем основном скрипте определены функции или классы, которые вы хотите использовать в другом месте, вы должны извлечь их в другой модуль. Но если что-то в другом модуле должно получить доступ к engine экземпляру из основного сценария, то вам придется переосмыслить свой дизайн, чтобы явно передать экземпляр engine (или все, что нужно от него).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...