Python 导入为未定义的全局名称
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/16346107/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Python import as global name not defined
提问by cswaim
I have an application that runs on Postgres & Mysql. Each program checks to determine the database and then imports either postgres_db as db_util or mysql_dt as db_util. All works well when code in main references db_util, but if a class is imported, the reference to db_util is not defined.
我有一个在 Postgres & Mysql 上运行的应用程序。每个程序检查以确定数据库,然后将 postgres_db 作为 db_util 或 mysql_dt 作为 db_util 导入。当 main 中的代码引用 db_util 时一切正常,但如果导入了一个类,则未定义对 db_util 的引用。
I created the following to classes and main to test the problem and found another interesting side effect. Classes B & C reference ClassA under different import cases. B & C are identical except B is in main and C is imported.
我为 classes 和 main 创建了以下内容来测试问题,并发现了另一个有趣的副作用。在不同的进口情况下,B 类和 C 类引用 A 类。B & C 是相同的,除了 B 是 main 并且 C 是进口的。
ClassX.py
类X.py
class ClassA(object):
def print_a(self):
print "this is class a"
class ClassC(object):
def ref_a(self):
print 'from C ref a ==>',
xa=ClassA()
xa.print_a()
def ref_ca(self):
print 'from C ref ca ==>',
xa=ca()
xa.print_a()
test_scope.py
测试范围.py
from classes.ClassX import ClassA
from classes.ClassX import ClassA as ca
from classes.ClassX import ClassC as cb
class ClassB(object):
def ref_a(self):
print 'from B ref a ==>',
xa=ClassA()
xa.print_a()
def ref_ca(self):
print 'from B ref ca ==>',
xa=ca()
xa.print_a()
print 'globals:',dir()
print 'modules','ca:',ca,'cb:',cb,'CA:',ClassA
print ''
print 'from main'
xb=ClassB()
xb.ref_a()
xb.ref_ca()
print ''
print 'from imports'
xbs=cb()
xbs.ref_a()
xbs.ref_ca()
And the results:
结果:
globals: ['ClassA', 'ClassB', '__builtins__', '__doc__', '__file__', '__name__', '__package__', 'ca', 'cb']
modules ca: <class 'classes.ClassX.ClassA'> cb: <class 'classes.ClassX.ClassC'> CA: <class 'classes.ClassX.ClassA'>
from main
from B ref a ==> this is class a
from B ref ca ==> this is class a
from imports
from C ref a ==> this is class a
from C ref ca ==>
Traceback (most recent call last):
File "test_scope.py", line 32, in <module>
xbs.ref_ca()
File "R:\python\test_scripts\scope\classes\ClassX.py", line 13, in ref_ca
xa=ca()
NameError: global name 'ca' is not defined
Press any key to continue . . .
From my test, I see that the object ca (imported as) is not available to the ClassC, however, the module ClassA is available (imported without as).
从我的测试中,我看到对象 ca(导入为)对 ClassC 不可用,但是,模块 ClassA 可用(不带 as 导入)。
- Why the difference between import and import as behavior? I am unclear why mains globals are not available to classes main imports.
- What is a good approach to dynamically determine appropriate db_util module to import and have it accessible to other imported classes?
- 为什么 import 和 import as 行为之间存在差异?我不清楚为什么 mains globals 不能用于类 main 导入。
- 动态确定要导入的适当 db_util 模块并使其他导入类可以访问它的好方法是什么?
Update:After reading yet another post on Namespaces: "Visibility of global variables from imported modules", I understand that in my example above the reason classA is available to ClassC is that A & C are in the same imported file, thus the same namespace.
更新:在阅读了关于命名空间的另一篇文章:“来自导入模块的全局变量的可见性”后,我明白在我上面的例子中,classA 对 ClassC 可用的原因是 A 和 C 位于同一个导入文件中,因此具有相同的命名空间.
So the remaining question is a design question:
所以剩下的问题是一个设计问题:
if I have code like this:
如果我有这样的代码:
if db == 'MySQL':
from mysql_db import db_util
elif db == 'Postgres'
from postgres_db import db_util
What is a good approach to make db_util available to all imported modules?
让 db_util 可用于所有导入的模块的好方法是什么?
UPDATE:
更新:
from the reponse by Blckknght, I added the code
根据 Blckknght 的回复,我添加了代码
cb.ca =ca
to the scope_test script. This requires the class call to xa=ca()be changed to xa=self.ca(). I also think that adding objects to a class from outside the class, though Python allows it, is not a good design methodology and will make debugging a nightmare.
到 scope_test 脚本。这需要对xa=ca()的类调用更改为xa=self.ca()。我还认为从类外部向类添加对象,虽然 Python 允许这样做,但不是一种好的设计方法,会使调试成为一场噩梦。
However, since I think modules and classes should be standalone or specifically declare their dependencies, I am going to implement the class like this, using the code sample from above.
但是,由于我认为模块和类应该是独立的或专门声明它们的依赖项,因此我将使用上面的代码示例来实现这样的类。
break out ClassA and ClassC to separate modules and at the top of ClassC, before the class definition, do the imports
拆分 ClassA 和 ClassC 以分隔模块,并在 ClassC 的顶部,在类定义之前,进行导入
from ClassA import ClassA
from ClassA import ClassA as ca
class ClassB(object):
and in my real situation, where I need to import the db_util module into several modules
在我的实际情况中,我需要将 db_util 模块导入到几个模块中
ci.py #new module to select class for appropriate db
ci.py #new 模块为适当的数据库选择类
if db == 'MySQL':
from mysql_db import db_util
elif db == 'Postgres'
from postgres_db import db_util
in each module needing the db_util class
在每个需要 db_util 类的模块中
import ci
db_util=ci.db_util #add db_util to module globals
class Module(object):
One problem with this is it requires each module using the db_util to import it, but it does make the dependencies known.
这样做的一个问题是它需要每个模块使用 db_util 来导入它,但它确实使依赖关系已知。
I will close this question and want to thank Blckknght and Armin Rigo for their responses which help clarify this issue for me. I would appreciate any design related feedback.
我将结束这个问题,并感谢 Blckknght 和 Armin Rigo 的回答,他们帮助我澄清了这个问题。我将不胜感激任何与设计相关的反馈。
采纳答案by Blckknght
In Python, each module has it's own global namespace. When you do an import, you're only adding the imported modules to the current module's namespace, not to the namespace of any other module. If you want to put it in another namespace, you need to tell Python this explicitly.
在 Python 中,每个模块都有自己的全局命名空间。执行导入时,您只是将导入的模块添加到当前模块的命名空间,而不是任何其他模块的命名空间。如果你想把它放在另一个命名空间中,你需要明确地告诉 Python。
main.py:
主要.py:
if db == "mysql": # or whatever your real logic is
import mysql_db as db_util
elif db == "postgres":
import postgres_db as db_util
import some_helper_module
some_helper_module.db_util = db_util # explicitly add to another namespace
#...
Other modules:
其他模块:
import some_helper_module
db = some_helper_module.db_util.connect() # or whatever the real API is
#...
Note that you can't usually use your main module (which is executed as a script) as a shared namespace. That's because Python uses the module's __name__attribute to determine how to cache the module (so that you always get the same object from multiple imports), but a script is always given a __name__of "__main__"rather than its real name. If another module imports main, they'll get a separate (duplicate) copy!
请注意,您通常不能将主模块(作为脚本执行)用作共享命名空间。这是因为 Python 使用模块的__name__属性来确定如何缓存模块(以便您始终从多个导入中获取相同的对象),但脚本总是被赋予一个__name__of"__main__"而不是它的真实名称。如果另一个模块导入main,他们将获得一个单独的(重复的)副本!
回答by Armin Rigo
You're approaching the problem with the wrong point of view. Every module is a namespace that starts empty and is filled with a name for (typically) each statement it runs:
您正在以错误的观点处理问题。每个模块都是一个以空开头的命名空间,并为(通常)它运行的每个语句填充一个名称:
import foo => defines foo
from foo import bar => defines bar
from foo import bar as baz => defines baz
class kls:
pass => defines kls
def fun():
pass => defines fun
var = 6 * 7 => defines var
Looking at ClassX.py we see that the name cais not defined in this module, but ClassAand ClassCare. So the execution of the line xa=ca()from ClassX.py fails.
纵观ClassX.py我们看到这个名字ca并不在此模块中定义的,而是ClassA和ClassC有。因此xa=ca()ClassX.py中的行的执行失败。
In general, the idea is that every single module imports what it needs. You can also patch a name "into" a module from outside, but this is generally considered very bad style (reserved for very special cases).
一般来说,这个想法是每个模块都导入它需要的东西。您也可以从外部将名称“插入”模块,但这通常被认为是非常糟糕的风格(保留用于非常特殊的情况)。

