我有一个函数和一个包含对该函数的引用的字典。
def func1(): print('blah')
dict1 = {'func1': func1}
如果我按照给定的顺序将它们粘贴到python解释器中,一切都很好。
`>>> def func1(): print('blah')
...
>>> func1
<function func1 at 0x7f8939d77730>
>>> func1()
blah
>>> dict1 = {'func1': func1}
>>> dict1['func1']()
blah
`
但是,如果我从文件中导入dict1
,解释器说func1
没有被定义,即使它被定义了。
因此,文件'dictfile.py'包含一行文本:
dict1 = {'func1': func1}
然后这进入解释器:
>>> def func1(): print('blah')
...
>>> func1()
blah
>>> from dictfile import *
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/../dictfile.py", line 1, in <module>
dict1 = {'func1': func1}
NameError: name 'func1' is not defined
>>>
这里发生了什么?
func1
未在您的dictfile.py
背景范围内定义。
'func1'的全局范围仅限于它自己定义的范围。这样它就可以作为一个独立的模块运行。也就是说,它可以作为一个模块运行:因此它可以被任何其他模块导入和运行。这样做是为了避免当不同模块在其全局定义中对不同的事物使用相同的名称时发生冲突。
从python docs:
因此,模块的作者可以在模块中使用全局变量,而不必担心与用户的全局变量的意外冲突。
通过使用import语句加载文件,可以将其作为模块。您不能期望该模块获取导入它的范围。它自己的范围仍然不同。它的完整性受到保护。如果它本身没有定义,它必须自己导入它使用的任何定义。
为了能够加载引用该函数的字典,必须在它所在的范围(文件)中定义该函数。
由于dictfile.py
文件对您的解释器的当前状态一无所知(您的状态未导入到文件中,我不确定是否可能),因此无法找到对该函数的引用。
根据Python docs,
每个模块都有自己的私有符号表,该表用作模块中定义的所有函数的全局符号表。因此,模块的作者可以在模块中使用全局变量,而不必担心与用户的全局变量的意外冲突。另一方面,如果您知道自己在做什么,则可以使用与其函数modname.itemname相同的符号来触摸模块的全局变量。
为了能够在模块(文件)范围内访问您的功能,您需要导入交互式解释器的“模块”,我认为这是不可能的。
每个模块都定义了一个名称空间,因此模块中的“全局”变量实际上是作用于该模块的;另一个模块可以访问它们,但它需要通过定义名称的模块来实现。
在交互式会话中运行时,您创建的对象将添加到名为__main__
的特殊模块中。如果需要,另一个模块可以从中导入东西,但我不推荐它。
仅作为学习目的的示例:
$ cat dictfile.py
from __main__ import func1
dict1 = {'func1': func1}
$ python
Python 2.7.10 (default, Jul 30 2016, 19:40:32)
[GCC 4.2.1 Compatible Apple LLVM 8.0.0 (clang-800.0.34)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> def func1(): print('blah')
...
>>> from dictfile import dict1
>>> dict1
{'func1': <function func1 at 0x102735c08>}
>>> dict1['func1']()
blah
在实际程序中,您应该避免像这样的循环依赖。但是从一个模块导入函数,将它们组装成另一个模块中的数据结构,然后使用第三个模块的数据结构仍然很有用。
关于程序各部分之间依赖关系的一个好的经验法则:实现应该只依赖于抽象,而抽象应该只依赖于其他抽象。