Перезагрузить подмодуль, импортированный в другие модули
У меня есть следующая проблема, и я поделюсь четырьмя различными файлами.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 для другого взгляда на это.