【问题标题】:Reload submodule imported in other modules重新加载其他模块中导入的子模块
【发布时间】:2019-03-14 13:36:38
【问题描述】:

我有以下问题,我将分享四个不同的 .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 时

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

适用于calculation_twochild002.py 运行,但它不会重新加载由child003.py 调用的calculation_two

更具体地说,如果您运行 master001.py 并且在手动输入任何内容之前更改 calculation_two 的内容,那么当您被询问时

reload child 1 function? Enter Y or N

你输入 N,当你被问到时

reload child 2 function? Enter Y or N

您输入 Y,您将看到 child003.py 返回的值未反映新更新的代码。

我阅读了 How do I unload (reload) a Python module?How to reload python module imported using `from module import *`,它们非常有帮助,但我找不到解决这个特定问题的方法。

【问题讨论】:

    标签: python python-3.x reload python-importlib


    【解决方案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']
    

    因为child003模块对象中的calculation_two引用是一个独立的标签。

    您要么必须手动替换该标签:

    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']
    

    我可以推荐阅读Ned Batchelder's explanation of Python names and values 以了解有关此问题的另一个观点。

    【讨论】:

    • 非常感谢您花时间撰写有用的解释。也谢谢你分享那个链接,我读了两遍,非常非常有帮助。拜托,我还有最后一个问题。如果我有多个子脚本,比如 child005.py、child009.py、child020.py eccetera 都使用“from child002 import calculation_two”,有没有办法检查我需要更新多少个孩子? (类似于你提到的“child003.calculation_two =calculation_two”,但假设我不知道有多少孩子引用了calculation_two)谢谢
    • @Angelo:您必须检查所有模块的功能并检查它们的__module__ 属性。如果您想定期重新加载模块,最好只在其他地方导入模块对象,而不是从这些模块中导入名称。
    • 谢谢你,Martijn。请问您说“在其他地方导入模块对象”是什么意思?你的意思是,以我上面的代码为例,在 child003.py 中我应该使用“import child”而不是“from child002 import calculation_two”吗?再次感谢您的所有帮助,非常感谢。
    • @Angelo:你会使用import child002,是的。
    猜你喜欢
    • 2017-04-03
    • 1970-01-01
    • 1970-01-01
    • 2012-12-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多