卖弄.朋友:
import subone
import subtwo
苏波呢.朋友:
a = 'abc'
苏炳添我.朋友:
print subone.a
运行python main.py
投掷NameError: name 'subone' is not defined
。我希望它打印'abc'。
重构它以使用from
import
和类没有帮助:
卖弄.朋友:
from subone import * # Only using from X import * for example purposes.
from subtwo import *
print 'from main.py:', a.out
苏波呢.朋友:
class A:
out = 'def'
a = A()
苏炳添我.朋友:
# This throws NameError: name 'a' is not defined
print a.out
# This throws NameError: name 'A' is not defined
b = A()
print b.out
但它将打印'from main.py:def'。 (它在使用import
时也有效。)
为什么这样工作?似乎一旦subone
进口,它应该可用于subtwo
。
这是因为导入的模块相互依赖而不通过“父”模块是不好的编程?还有另一种标准方法吗?
我现在明白第一个例子不起作用,因为行print subone.a
不识别名称subone
,它不在subtwo
的命名空间中(即使它在main.py
中),并且它是从模块subtwo
中调用的。这可以通过在import subone
顶部使用subtwo.py
来修复 - 它不会重新加载模块,但会将其添加到subtwo
的命名空间,因此subtwo
可以使用它。
但是这个怎么样:
卖弄.朋友:
from subone import Nugget
from subtwo import Wrap
wrap = Wrap()
print wrap.nugget.gold
苏波呢.朋友:
class Nugget:
gold = 'def'
苏炳添我.朋友:
class Wrap:
nugget = Nugget()
我认为,因为Wrap
和Nugget
都被直接加载到main
的命名空间,他们将使用main
的命名空间并能够互相引用,但它会抛出一个NameError: name 'Nugget' is not defined
。这是因为Wrap
是在加载到subtwo
的命名空间之前从main
的命名空间中进行评估/检查的吗?
如果您以这种方式修改了subtwo.py,那么它将起作用
import subone
print subone.a
当你在subtwo.py中执行subone.a时,你试图访问subtwo.py和命名空间“subone”中的命名空间subone,应该有一个属性“a”。
当你这样做 - 在subtwo.py中导入subone时,subone被添加到命名空间,subone命名空间有属性a。所以subone.a会起作用。
我还建议您使用dir()来查看如何添加命名空间。
在subtwo.py中,您可以执行以下操作:
print dir()
import subone
print dir()
print subone.a
同样,尝试在导入语句之前和之后添加“print dir()”,这个想法应该变得清晰。
“import x”将“x”添加到当前模块名称空间,而“from x import *”将所有模块级属性直接添加到当前模块名称空间
因此,在上面的main.py,subone.py和subtwo.py的第一个示例中,main.py中的命名空间将包含'subone'和'subtwo',而subtwo.py将具有空命名空间并且无法访问subone.a 。
[编辑:更多解释]请考虑以下文件:main.py
print "Before importing subone : ", dir()
import subone
print "After importing subone and before importing subtwo: ", dir()
import subtwo
print "After importing subone and subtwo: ", dir()
苏波呢.朋友
a = 'abc'
苏炳添我.朋友
print dir()
import subone
print "module level print: ", subone.a
print dir()
def printX():
print subone.a
并运行main.py的输出:
Before importing subone : ['__builtins__', '__doc__', '__file__', '__name__', '__package__']
After importing subone and before importing subtwo: ['__builtins__', '__doc__', '__file__', '__name__', '__package__', 'subone']
['__builtins__', '__doc__', '__file__', '__name__', '__package__']
module level print: abc
['__builtins__', '__doc__', '__file__', '__name__', '__package__', 'subone']
After importing subone and subtwo: ['__builtins__', '__doc__', '__file__', '__name__', '__package__', 'subone', 'subtwo']
一些观察
你能解释一下为什么你觉得subone应该可用于subwo,当subone被main导入时?实际上,可以在不知道main.py导入了什么的情况下编译了subtwo.py。
另外,如果第二个程序导入了subtwo.py,那么subwo对subone的了解是否取决于两个主程序中哪一个导入了subwo?这会降低subtwo的可重用性。
看起来您正在考虑将编译作为具有已定义顺序的进程,累积状态信息:编译main.py,在此期间我们编译/导入subone.py,从中累积信息,然后编译/导入subtwo。 py,使用我们已经积累的信息。
相反,除非声明依赖关系,否则每个模块的编译都独立于其他模块。这使得重用和维护代码变得更加容易:隐藏的依赖项更少。
这是因为导入的模块相互依赖而不通过“父”模块是不好的编程?
不是这样的......让模块2依赖于模块1而不是这样说是错误的编程,即没有模块2声明“我依赖于模块1”。
除非您将subtwo
导入其中,否则subone
命名空间将完全为空。
就编程实践而言,如果需要,subone
和subtwo
可以相互依赖,你只需要明确地链接它们(用import
)
关于你的第二个例子,“main.py”知道Nugget
,但“subtwo.py”不知道。
我认为以这种方式思考会有所帮助。每个模块(文件)都必须像现有的其他模块一样工作。在这种情况下,“subtwo.py”将无法自行运行,因为它没有导入Nugget
。基本上“subtwo.py”不知道“main.py”知道什么。它不应该,因为它可以被任何人从任何地方调用,并且它不能依赖于其他任何人导入它需要的东西。
这是因为导入的模块有自己独立的命名空间。你写的非常像:
def func1():
a = 1
def func2():
print a
func1()
func2() # This will throw an error
a = 2
func2() # Now this will print 2.
模块在本地具有命名空间,当您使用from subone import *
时,只将命名空间导入main.py
命名空间,subtwo
无法访问该命名空间。
然而 - 你要做的是非常糟糕的做法。避免使用全局变量和import *
,因为你会像现在这样越来越困惑。
更多信息:https://docs.python.org/3/reference/import.html
https://bytebaker.com/2008/07/30/python-namespaces/
http://www.diveintopython.net/html_processing/locals_and_globals.html
也许:http://sebastianraschka.com/Articles/2014_python_scope_and_namespaces.html