我创建了一个带有单个函数的Python模块,只打印'a!'。我打开了Python解释器并用2种不同的语法导入了模块
>>> import a
>>> from a import func
>>> func()
a!
>>> a.func()
a!
此时我更改了func以打印其他内容,然后再次评估
>>> func()
a!
>>> a.func()
a!
当然,由于模块未重新加载,因此可以预期。然后我重新加载模块并期望两个函数都更新,但是:
>>> reload(a)
<module 'a' from 'a.py'>
>>> a.func()
aasd!
>>> func()
a!
只有a.func似乎更新。我一直认为Python只保留同一模块的单个实例,但现在似乎有两个。我做了进一步的测试以验证我的声明,并在模块的顶层添加了一个print语句,然后重新启动了解释器并再次导入:
>>> import a
module imported
>>> import a
>>> from a import func
这让我更加困惑,因为我希望看到“模块导入”两次。我做的第三个实验是全局变量实验:
>>> import a
module imported
>>> from a import GLOBAL_VAR
>>> GLOBAL_VAR = 5
>>> a.GLOBAL_VAR
1
>>> GLOBAL_VAR
5
>>> GLOBAL_VAR is a.GLOBAL_VAR
False
所以有一个模块的实例,但内部对象的不同实例?如何以这种行为实施Gevent's monkey patching?
答案 0 :(得分:7)
一个模块一旦导入,就只是另一个python对象。因此,看到以下示例,您的结果应该不会让您感到惊讶:
x = SomeObject()
x.y = 1
a = x.y
x.y = 2
print(a) #a is still 1, not 2
执行from module import name
时,会在当前命名空间中创建变量name
,该变量包含对导入事物的引用(无论是包/模块/类/其他)。它是以下的语法糖:
import module
name = module.name
现在,当您重新加载module
时,您显然不会更新引用name
保留。
关于您的第二个实验,导入后,模块会在sys.modules
中缓存;后续导入将利用缓存。因此,直接在模块级别的所有代码(例如print
)将仅在第一次导入时执行。
答案 1 :(得分:2)
重新加载模块时,其中的所有功能都会重新加载到当前模块中。但是当您从模块导入特定函数时,它将成为当前模块的本地函数。因此,改变一个不会影响另一个。
检查出来:
import math
from math import factorial
print locals()
print id(math.factorial), id(factorial)
math.factorial, factorial = 0, 1
print id(math.factorial), id(factorial)
reload(math)
print id(math.factorial), id(factorial)
from math import factorial
print id(math.factorial), id(factorial)
<强>输出强>
{'__builtins__': <module '__builtin__' (built-in)>,
'__file__': '/home/thefourtheye/Desktop/Test.py',
'__package__': None,
'factorial': <built-in function factorial>, # Factorial is in the local context
'__name__': '__main__',
'__doc__': None,
'math': <module 'math' (built-in)>}
39346504 39346504
33545712 33545688
39346504 33545688
39346504 39346504
id
在CPython实现中打印内存中对象的地址
答案 2 :(得分:0)
我刚刚确认的事情是Python的特定会话确保只有一个特定模块的实例(更具体地说是文件路径)。
证明(使用单个Python会话):
foobar.py:
a = 123
def foo(): print a
的Python:
>>> from foobar import foo
>>> foo()
123
更改foobar.py:
a = 1234
def foo(): print a;print a
的Python:
>>> reload(foobar)
<module 'foobar' from 'c:\foobar.py'>
>>> foobar.foo()
1234
1234
>>> foo()
1234
>>> id(sys.modules[foo.__module__]) == id(sys.modules[foobar.foo.__module__])
True
导致不同输出的唯一因素是code
对象,(foo.__globals['a']
和foobar.foo.__globals__['a']
是相同的)
>>> id(foo.__code__) == id(foobar.foo.__code__)
False
不知道Gevent
猴子补丁。
答案 3 :(得分:-1)
在Python中,变量是名称,而不是容器。一切都是一个对象,一切都是参考,而变量都不是。变量引用对象和名称空间将名称映射到对象。您可以使用模块来组织代码,每个模块都会在首次导入时执行。
因此,在导入a b后,b引用对象a,a将保持不变,除非您修改对象a(如果a是可变的)。当您重新加载(a)时,您只需为变量分配一个新对象,这与b完全无关。
>>> a = 1
>>> b = a
>>> a = 2
>>> print b
1
>>> import a
>>> from a import func
>>> id(func)
4324575544
>>> id(a.func)
4324575544
>>> reload(a)
<module 'a' from 'a.py'>
>>> id(a.func)
4324576624
>>> id(func)
4324575544