Перезагрузить подмодуль, импортированный в другие модули

У меня есть следующая проблема, и я поделюсь четырьмя различными файлами.py, чтобы лучше объяснить себя. Я бегу код из Spyder (не Jupyter), Python 3.4. У меня есть мастер-скрипт "master001.py", из которого я выполняю код. это выглядит так:

import sys
before = [str(m) for m in sys.modules]

from importlib import reload
import time
#from child001 import calculation as calc
import child001 
from child002 import calculation_two
from child003 import calculation_three

after = [str(m) for m in sys.modules]
print("########################")   
print([m for m in after if not m in before])
print("########################\n")




stop = False
while stop == False:
    print("\n\n\n\n\n\n\n")
    reload_child_one = input("reload child 1 function? Enter Y or N\n")
    reload_child_one = reload_child_one.lower()

    if reload_child_one == "y":
        print("Script will try to reload the calculation 1 / child 1 module.")
        time.sleep(1)
        reload(child001)



    reload_child_two = input("reload child 2 function? Enter Y or N\n")
    reload_child_two = reload_child_two.lower()

    if reload_child_two == "y":
        print("Script will try to reload the calculation 2 / child 2 module.")
        time.sleep(1)
        #reload(sys.modules[calculation_two.__module__])
        #del calculation_two
        #from child002 import calculation_two
        #__import__("child002", fromlist='calculation_two')
        calculation_two = reload(sys.modules["child002"]).calculation_two



    print("\n####################################################")
    a = input("Enter number that will be saved in variable 'a' or enter Q to quit prorgam\n")

    if a.lower() == "q" :
        stop = True
        print("\nFunction complted. Script will quit.")
        print("####################################################\n")
        time.sleep(2)

    else:
        try:
            a = int(a)

            print("Master - Launching Child function 'calculation'")
            b = child001.calculation(a)

            print("\nMaster - Inside Master file. Result = b = {}".format(b))
            print("####################################################\n")

            print("Master - Launching Child 2 function 'calculation_two' on input variable")
            c = calculation_two(a)     

            print("\nMaster - Inside Master file. Result = c = {}".format(c))            
            print("####################################################\n")

            print("Master - Launching child 3")
            calculation_three()
            time.sleep(2)

        except:
            print("input value was not a valid number. Please, try again.\n")
            print("####################################################\n")
            time.sleep(2)

master001.py вызывает child001.py для выполнения простого вычисления:

print("wassupp from child 1 !!!")

def calculation(a):

    print("\n----------------------------------------")
    print("Child 1 - function 'calculation' started.")
    print("Child 1 - Operation that will be executed is: input variable + 20")

    result = a + 20

    print("Child 1 - Returning result =  {}".format(result))
    print("----------------------------------------\n")
    return result

Затем master001.py вызывает child002.py, в котором выполняется еще один простой расчет:

print("wassupp from child 2 !!!")

def calculation_two(a):

    print("\n----------------------------------------")
    print("Child 2 - function  'calculation_two' started.")
    print("Child 2 - Operation that will be executed is: input variable + 200")

    result = a + 200

    print("Child 2 - Returning result =  {}".format(result))
    print("----------------------------------------\n")
    return result

Все идет нормально. Наконец, у меня есть child003.py. в этом модуле я выполняю вычисление, которое фактически импортируется из child002.py

from child002 import calculation_two

print("wassupp from child 3 !!!")

def calculation_three():

    print("\n----------------------------------------")
    print("Child 3 function - Calculation will use the one in child 2 applied to value '3'.!\n")

    result = calculation_two(3)

    print("Child 3 - result =  {}".format(result))
    print("----------------------------------------\n")
    return

как вы можете видеть из запуска master001.py, когда я перезагружаю

calculation_two = reload(sys.modules["child002"]).calculation_two

это работает для calculation_two бежать от child002.py, однако он не перезагружается calculation_two называется child003.py,

Более конкретно, если вы запустите master001.py и перед ручным вводом чего-либо измените содержимое calculation_twoтогда, когда вас спросят

reload child 1 function? Enter Y or N

вы вводите N, и когда вас спросят

reload child 2 function? Enter Y or N

введите Y, вы увидите значение, возвращаемое child003.py не отражает новый обновленный код.

Я читаю Как выгрузить (перезагрузить) модуль Python? и Как перезагрузить Python-модуль, импортированный с помощью `from module import *`, они очень полезны, но я не могу найти там решения этой конкретной проблемы.

1 ответ

Решение

Ваша проблема в том, как вы импортировали функцию из child002:

from child002 import calculation_two

Это создает ссылку на объект функции в child003и эта ссылка не заменяется. Имена Python похожи на метки на строках, привязанные к объектам. Вы можете привязать несколько меток к объекту, и если вы хотите заменить этот объект на другой, то вы должны убедиться, что все эти метки связаны заново.

Вы начинаете с этого:

sys.modules['child002']
    -> module object created from child002.py
        -> module.__dict__ (the module globals)
            -> module.__dict__['calculation_two']
                    |
                    |
                    +--> function object named calculation_two
                    |
                    |
            -> module.__dict__['calculation_two']
        -> module.__dict__ (the module globals)
    -> module object for child003.py
sys.modules['child003']

и когда вы затем перезагрузите child002 модуль Python заменяет все существующие глобальные переменные новыми объектами, так что теперь у вас есть:

sys.modules['child002']
    -> module object created from child002.py
        -> module.__dict__ (the module globals)
            -> module.__dict__['calculation_two']
                    |
                    |
                    +--> *new* function object named calculation_two


                    +--> *old* function object named calculation_two
                    |
                    |
            -> module.__dict__['calculation_two']
        -> module.__dict__ (the module globals)
    -> module object for child003.py
sys.modules['child003']

поскольку calculation_two ссылка в child003 Объект модуля является независимой меткой.

Вы должны либо заменить этот ярлык вручную:

calculation_two = reload(sys.modules["child002"]).calculation_two
child003.calculation_two = calculation_two

или вы можете просто не ссылаться calculation_two непосредственно, а вместо этого ссылаться только на child002 модуль:

import child002

# ...

def calculation_three():
    # ...
    result = child002.calculation_two(3)

в этот момент у вас есть следующие отношения:

sys.modules['child002']
    -> module object created from child002.py
       ^ -> module.__dict__ (the module globals)
       |    -> module.__dict__['calculation_two']
       |            |
       |            |
       |            +--> function object named calculation_two
       |
       |
       +------------+
                    |
                    |
            -> module.__dict__['child002']
        -> module.__dict__ (the module globals)
    -> module object for child003.py
sys.modules['child003']

Я могу рекомендовать прочитать объяснение Неда Батчелдера об именах и значениях Python для другого взгляда на это.

Другие вопросы по тегам