假设我有3个文件:
a.py
from d import d
class a:
def type(self):
return "a"
def test(self):
try:
x = b()
except:
print "EXCEPT IN A"
from b import b
x = b()
return x.type()
b.py
import sys
class b:
def __init__(self):
if "a" not in sys.modules:
print "Importing a!"
from a import a
pass
def type(self):
return "b"
def test(self):
for modules in sys.modules:
print modules
x = a()
return x.type()
c.py
from b import b
import sys
x = b()
print x.test()
并运行python c.py
Python回来抱怨:
NameError:全局名称'a'不是 定义
但是,sys.modules中的IS:
copy_reg
sre_compile
locale
_sre
functools
encodings
site
__builtin__
operator
__main__
types
encodings.encodings
abc
errno
encodings.codecs
sre_constants
re
_abcoll
ntpath
_codecs
nt
_warnings
genericpath
stat
zipimport
encodings.__builtin__
warnings
UserDict
encodings.cp1252
sys
a
codecs
os.path
_functools
_locale
b
d
signal
linecache
encodings.aliases
exceptions
sre_parse
os
我可以改变b.py这样:
x = a()
更改为
x = sys.modules [“a”]。a()
python很乐意运行它。
由此产生了几个问题:
为什么python说它不知道是什么,当它在sys.modules中时?
使用sys.modules是一种“正确”的方式来访问类和函数定义吗?
导入模块的“正确”方式是什么?
即
来自模块导入x
或
导入模块
答案 0 :(得分:3)
我想这是一个范围问题,如果你在构造函数中导入一个模块,你只能在构造函数中使用它,在import语句之后。
答案 1 :(得分:2)
导入语句分两步执行:(1)找到一个模块,并在必要时进行初始化; (2)在本地命名空间中定义一个或多个名称 (导入语句发生的范围)。
所以问题在于,即使已导入模块a
,名称a
也仅限于b.__init__
方法的范围,而不是b.py
的整个范围。 1}}。因此,在b.test
方法中,没有此类名称a
,因此您获得了NameError
。
您可能需要阅读此article on importing Python modules,因为它有助于解释使用import
的最佳做法。
答案 2 :(得分:1)
在你的情况下,a在sys.modules中..但不是sys.modules中的所有内容都在b的范围内。如果你想使用re,你也必须导入它。
有条件导入有时是可以接受的,但这不是其中之一。首先,在这种情况下,a和b之间的循环依赖是不幸的,应该避免(在Fowler的Refactoring中这样做很多模式)。那就是说,没有必要在这里有条件地导入。
b应该简单地导入一个。你想通过不直接在文件顶部导入它来避免什么?
答案 3 :(得分:0)
基于程序逻辑有条件地导入代码模块是一种糟糕的风格。名称应始终在代码中的任何位置表示相同的内容。想一想这对调试有多困惑:
if (something)
from office import desk
else
from home import desk
... somewhere later in the code...
desk()
即使你没有范围问题(你很可能会有),但它仍然令人困惑。
将所有导入语句放在文件的顶部。那是其他程序员寻找它们的地方。
至于是否使用“来自foo import bar”的经文只是“import foo”,权衡更多的是打字(必须输入“foo.bar()”或只输入“bar()”)清晰度和特异性。如果您希望您的代码真正可读且毫不含糊,只需说出“import foo”并在所有地方完全指定调用。请记住,阅读代码比编写代码要困难得多。