从模块重新加载的Python递归函数

从模块重新加载的Python递归函数,python,function,object,recursion,python-module,Python,Function,Object,Recursion,Python Module,如果我们在模块mod1中有递归函数func1,并且我们使用这两条语句导入它: import mod1 及 基本上,我们将有两个指向单个对象的链接: id(func1) == id(mod1.func1) 然后,如果我们更新mod1.py文件中的func1代码,然后重新加载mod1,而不是函数(func1)本身: 我们将有两个不同的对象: id(func1) != id(mod1.func1) 但是,如果我们调用func1(*args)-首先调用它调用func1,但随后所有递归调用它都调用m

如果我们在模块mod1中有递归函数func1,并且我们使用这两条语句导入它:

import mod1

基本上,我们将有两个指向单个对象的链接:

id(func1) == id(mod1.func1)
然后,如果我们更新mod1.py文件中的func1代码,然后重新加载mod1,而不是函数(func1)本身:

我们将有两个不同的对象:

id(func1) != id(mod1.func1)
但是,如果我们调用func1(*args)-首先调用它调用func1,但随后所有递归调用它都调用mod1.func1

这是python中所期望的行为吗

以下是代码示例: mod1.py:

然后修改:

def func1(n):
  # print("n is: {}".format(n))
  if n==0: return 1
  return n*func1(n-1)
以下是REPL输出:

>>> from mod1 import func1
>>> func1(2)
n is: 2
n is: 1
n is: 0
2
>>> import mod1
>>> mod1.func1(2)
n is: 2
n is: 1
n is: 0
2
>>> id(func1)
4304551720
>>> id(mod1.func1)
4304551720
>>> ## ** Here mod1 code is updated: ** ##
>>> import imp
__main__:1: DeprecationWarning: the imp module is deprecated in favour of importlib; see the module's documentation for alternative uses
>>> imp.reload(mod1)
<module 'mod1' from '/home/user/workspace/python/tests/mod1.py'>
>>> id(mod1.func1)
4305274128
>>> id(func1)
4304551720
>>> mod1.func1(2)
2
>>> func1(2)
n is: 2
2
>>> 
>>来自mod1导入功能1
>>>职能1(2)
n是:2
n是:1
n是:0
2.
>>>导入mod1
>>>mod1.func1(2)
n是:2
n是:1
n是:0
2.
>>>id(功能1)
4304551720
>>>id(mod1.func1)
4304551720
>>>##**这里更新了mod1代码:**##
>>>进口小商品
__主要提示:1:弃用警告:imp模块已弃用,取而代之的是importlib;有关替代用途,请参阅模块文档
>>>imp.reload(模块1)
>>>id(mod1.func1)
4305274128
>>>id(功能1)
4304551720
>>>mod1.func1(2)
2.
>>>职能1(2)
n是:2
2.
>>> 
这似乎有点令人困惑。
在python中,这是一个需要的行为吗?

很难说这个行为是否需要(对谁来说),但它是需要的

您的代码示例与以下代码之间没有太大区别:

In [3]: class Foo:
   ...:     def qwe(self, once_again=True):
   ...:         print('original qwe')
   ...:         if once_again:
   ...:             self.qwe(once_again=False)
   ...:     qwe1 = qwe
   ...:
   ...:     def qwe(self, once_again=True):
   ...:         print('new qwe')
   ...:         if once_again:
   ...:             self.qwe(once_again=False)
   ...: a = Foo()
   ...: a.qwe1()
   ...:
   ...:
original qwe
new qwe
执行import语句后,
mod1
func1
只是保持对相应对象的引用的变量。重新加载模块时,只需将另一个值指定给名为
mod1
的变量

BTW,当您在变量中存储对模块级或类级记录器的引用时,可以观察到类似的效果:<代码>日志=日志记录。GETLoggGER(γ-NAMEYSY),因为没有任何东西阻止您的代码的用户在应用程序生命周期的中间某处调用<代码>日志。如果较新的配置旨在抑制模块的输出,则代码将不知道模块的新记录器的任何信息,并且您将继续写入日志

我得说,这种行为至少是有意的

UPD:问题变得有点复杂


如果该变量在函数的当前词法范围内缺失,则从模块范围中获取该变量(如果该变量不是闭包,则使用
\uuuuuuuu闭包\uuuu
字段)。为了获得模块的范围,函数通过
sys.modules[func1.\uuuu module\uuuu]
访问模块级变量,该变量已通过
reload

更新,这很有趣,但很难回答关于可取性的部分。。。
def func1(n):
  # print("n is: {}".format(n))
  if n==0: return 1
  return n*func1(n-1)
>>> from mod1 import func1
>>> func1(2)
n is: 2
n is: 1
n is: 0
2
>>> import mod1
>>> mod1.func1(2)
n is: 2
n is: 1
n is: 0
2
>>> id(func1)
4304551720
>>> id(mod1.func1)
4304551720
>>> ## ** Here mod1 code is updated: ** ##
>>> import imp
__main__:1: DeprecationWarning: the imp module is deprecated in favour of importlib; see the module's documentation for alternative uses
>>> imp.reload(mod1)
<module 'mod1' from '/home/user/workspace/python/tests/mod1.py'>
>>> id(mod1.func1)
4305274128
>>> id(func1)
4304551720
>>> mod1.func1(2)
2
>>> func1(2)
n is: 2
2
>>> 
In [3]: class Foo:
   ...:     def qwe(self, once_again=True):
   ...:         print('original qwe')
   ...:         if once_again:
   ...:             self.qwe(once_again=False)
   ...:     qwe1 = qwe
   ...:
   ...:     def qwe(self, once_again=True):
   ...:         print('new qwe')
   ...:         if once_again:
   ...:             self.qwe(once_again=False)
   ...: a = Foo()
   ...: a.qwe1()
   ...:
   ...:
original qwe
new qwe