Python:为什么导入的模块不能引用另一个导入的模块?

问题描述 投票:10回答:5

卖弄.朋友:

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

这是因为导入的模块相互依赖而不通过“父”模块是不好的编程?还有另一种标准方法吗?

Update:

我现在明白第一个例子不起作用,因为行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()

我认为,因为WrapNugget都被直接加载到main的命名空间,他们将使用main的命名空间并能够互相引用,但它会抛出一个NameError: name 'Nugget' is not defined。这是因为Wrap是在加载到subtwo的命名空间之前从main的命名空间中进行评估/检查的吗?

python import module
5个回答
6
投票

如果您以这种方式修改了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']

一些观察

  1. 您会注意到导入模块subtwo.py时,会立即执行print语句。
  2. 因此,当在main.py中导入subone和subtwo时,main.py的命名空间会被扩充。
  3. 这并不意味着将增加subtwo的命名空间。所以“a”只能通过subone.a在main.py中使用
  4. 当我们在subtwo.py中导入subone时,subwo的命名空间用subone扩充,而subow.py中的模块subone属性可通过subone.a获得。

3
投票

你能解释一下为什么你觉得subone应该可用于subwo,当subone被main导入时?实际上,可以在不知道main.py导入了什么的情况下编译了subtwo.py。

另外,如果第二个程序导入了subtwo.py,那么subwo对subone的了解是否取决于两个主程序中哪一个导入了subwo?这会降低subtwo的可重用性。

看起来您正在考虑将编译作为具有已定义顺序的进程,累积状态信息:编译main.py,在此期间我们编译/导入subone.py,从中累积信息,然后编译/导入subtwo。 py,使用我们已经积累的信息。

相反,除非声明依赖关系,否则每个模块的编译都独立于其他模块。这使得重用和维护代码变得更加容易:隐藏的依赖项更少。

这是因为导入的模块相互依赖而不通过“父”模块是不好的编程?

不是这样的......让模块2依赖于模块1而不是这样说是错误的编程,即没有模块2声明“我依赖于模块1”。


2
投票

除非您将subtwo导入其中,否则subone命名空间将完全为空。

就编程实践而言,如果需要,subonesubtwo可以相互依赖,你只需要明确地链接它们(用import


0
投票

关于你的第二个例子,“main.py”知道Nugget,但“subtwo.py”不知道。

我认为以这种方式思考会有所帮助。每个模块(文件)都必须像现有的其他模块一样工作。在这种情况下,“subtwo.py”将无法自行运行,因为它没有导入Nugget。基本上“subtwo.py”不知道“main.py”知道什么。它不应该,因为它可以被任何人从任何地方调用,并且它不能依赖于其他任何人导入它需要的东西。


0
投票

这是因为导入的模块有自己独立的命名空间。你写的非常像:

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

© www.soinside.com 2019 - 2024. All rights reserved.