我是Python的新手,并且有一段时间以来一直困扰着我的东西。我在Mark Lutz的“学习Python”中读到,当我们使用from
语句导入模块中存在的名称时,它首先导入模块,然后为其指定一个新名称(即函数的名称) ,类等存在于导入的模块中),然后使用del
语句删除模块对象。但是,如果我尝试使用引用自身未导入的导入模块中的名称的from
导入名称会发生什么?请考虑以下示例,其中有两个模块mod1.py
和mod2.py
:
#mod1.py
from mod2 import test
test('mod1.py')
#mod2.py
def countLines(name):
print len(open(name).readlines())
def countChars(name):
print len(open(name).read())
def test(name):
print 'loading...'
countLines(name)
countChars(name)
print '-'*10
现在看看当我运行或导入mod1时会发生什么:
>>>import mod1
loading...
3
44
----------
在我导入并运行test
函数时,虽然我甚至没有导入countChars
或countLines
,但from
语句已被删除,但它已成功运行mod2
模块对象。
所以我基本上需要知道为什么这个代码工作,即使考虑到我提到它不应该的问题。
编辑:Thanx很多人回答:)
答案 0 :(得分:6)
每个函数都有一个__globals__
属性,该属性包含搜索全局变量和函数的环境的引用。
然后test
函数链接到mod2
的全局变量。因此,当它调用countLines
时,即使您在导入函数的模块中编写了一个具有相同名称的新函数,解释器也总能找到正确的函数。
答案 1 :(得分:4)
我认为你正在与python处理namespaces
的方式搏斗。当您键入from module import thing
时,您将thing
从module
带入当前命名空间。因此,在您的示例中,导入mod1
时,将按以下顺序评估代码:
from mod2 import test #Import mod2, bring test function into current module namespace
test("mod1.py") #run the test function (defined in mod2)
现在对于mod2:
#create a new function named 'test' in the current (mod2) namespace
#the first time this module is imported. Note that this function has
#access to the entire namespace where it is defined (mod2).
def test(name):
print 'loading...'
countLines(name)
countChars(name)
print '-'*10
所有这一切都很重要的原因是因为python允许您准确选择要引入命名空间的内容。例如,假设您有一个定义函数module1
的{{1}}。现在您正在编写另一个模块(cool_func
),因为module2
也有一个函数module2
。 Python允许您将它们分开。在cool_func
你可以做到:
module3
或者,你可以这样做:
import module1
import module2
module1.cool_func()
module2.cool_func()
或者你可以这样做:
from module1 import cool_func
import module2
cool_func() #module1
module2.cool_func()
可能性继续......
希望我的观点很明确。从模块导入对象时,您将选择在当前命名空间中引用该对象的方式。
答案 2 :(得分:3)
其他答案比这个答案更明确,但如果您运行以下内容,则可以看到countChars
和countLines
实际上都是test.__globals__
中定义的:
from pprint import pprint
from mod2 import test
pprint(test.__globals___)
test('mod1')
您可以看到导入test
带来mod2
中定义的其他全局变量,让您运行该函数而不必担心必须导入所需的所有内容。
答案 3 :(得分:1)
每个模块都有自己的范围。在mod1
内,您无法使用名称countLines
或countChars
(或mod2
)。
mod2
本身不会受到影响,至少它是如何在其他地方导入的;其中定义的所有名称都可在模块中使用。
如果您引用的网页确实表示使用del
语句删除了模块对象,那就错了。 del
仅删除名称,不会删除对象。
答案 4 :(得分:1)
import
语句将整个模块加载到内存中,这就是test()
函数成功运行的原因。
但是,当您使用from
语句时,这就是您无法直接使用countLines
和countChars
但test
肯定会调用它们的原因。
from
语句基本上加载整个模块,并将导入的函数,变量等设置为全局命名空间。
例如。
>>> from math import sin
>>> sin(90) #now sin() is a global variable in the module and can be accesed directly
0.89399666360055785
>>> math
Traceback (most recent call last):
File "<pyshell#2>", line 1, in <module>
math
NameError: name 'math' is not defined
>>> vars() #shows the current namespace, and there's sin() in it
{'__builtins__': <module '__builtin__' (built-in)>, '__file__': '/usr/bin/idle', '__package__': None, '__name__': '__main__', 'main': <function main at 0xb6ac702c>, 'sin': <built-in function sin>, '__doc__': None}
考虑一个简单的文件,file.py:
def f1():
print 2+2
def f2():
f1()
仅导入f2:
>>> from file import f2
>>> f2()
4
虽然我只导入了f2()
而不是f1()
但它成功运行了f1()
因为模块已加载到内存中但我们只能访问f2()
,但是{{1可以访问模块的其他部分。
答案 5 :(得分:1)
来自A GUIDE TO PYTHON NAMESPACES,
尽管模块有自己的全局命名空间,但这并不意味着可以从模块中的任何位置使用所有名称。范围是指程序的一个区域,在该区域中可以访问名称空间而无需前缀。范围对于它们在模块中提供的隔离很重要。在任何时候都有许多作用域:你所在的当前函数的范围,模块的范围,然后是Python内置函数的作用域。这种范围嵌套意味着一个函数无法访问另一个函数内的名称。
还会在内部搜索名称空间的名称。这意味着如果在模块的全局命名空间中声明了某个名称,则可以在函数内重用该名称,同时确定任何其他函数将获取全局名称。当然,您可以通过在名称前加上'global'关键字来强制该函数使用全局名称。但是如果你需要使用它,那么你可能最好使用类和对象。