2013-05-02 37 views
3

我有一个应用程序在Postgres上运行& Mysql。每个程序检查以确定数据库,然后以db_util或db_util的形式导入postgres_db作为db_util或mysql_dt。当主引用db_util中的代码都运行良好时,但如果导入了类,则未定义对db_util的引用。Python导入为全局名称未定义

我创建了以下类和主要测试问题,并发现另一个有趣的副作用。 B类& C参考不同导入情况下的ClassA。 B & C是相同的,除了B在主要和C是进口。

ClassX.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

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() 

而且结果:

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 . . . 

从我的测试中,我看到的对象CA(进口AS)是不可用于ClassC,但是,ClassA模块可用(导入时不带)。

  1. 为什么导入和导入之间的区别是行为?我不清楚为什么主要全球供应商不能上课。
  2. 什么是动态确定适当的db_util模块导入并让其他导入的类可访问的好方法?

更新: 阅读命名空间的另一个职务后:“Visibility of global variables from imported modules”,据我所知,在我的例子上述原因ClassA的是提供给ClassC是,& C是在同一个导入文件,因此相同的命名空间。

所以剩下的问题是一个设计问题:

,如果我有这样的代码:

if db == 'MySQL': 
    from mysql_db import db_util 
elif db == 'Postgres' 
    from postgres_db import db_util 

什么是一个好方法,使db_util适用于所有进口的模块?

UPDATE:

从Blckknght的效应初探,我加入了代码

cb.ca =ca 

到scope_test脚本。这需要的类呼叫xa = ca()被更改为xa = self.ca()。我也认为,虽然Python允许将对象添加到类外,但这不是一个好的设计方法,它将使调试成为一场噩梦。

但是,因为我认为模块和类应该是独立的或专门声明它们的依赖关系,所以我将使用上面的代码示例来实现类。

突围ClassA和ClassC分离模块,并在ClassC的顶部,类定义之前,做进口

from ClassA import ClassA 
from ClassA import ClassA as ca 

class ClassB(object): 

,并在我的实际情况,在那里我需要将db_util模块导入数模块

ci.py #NEW模块在每个模块中,选择适当的类分贝

if db == 'MySQL': 
    from mysql_db import db_util 
elif db == 'Postgres' 
    from postgres_db import db_util 

需要的db_util类

import ci 
db_util=ci.db_util   #add db_util to module globals 

class Module(object): 

这样做的一个问题是它需要每个模块使用db_util来导入它,但它确实使依赖性已知。

我会关闭这个问题,并希望感谢Blckknght和Armin Rigo的回复,这些回复有助于为我解释这个问题。我会很感激任何与设计有关的反馈。

回答

9

在Python中,每个模块都有它自己的全局名称空间。当您执行导入时,您只会将导入的模块添加到当前模块的名称空间,而不是添加到任何其他模块的名称空间。如果你想把它放在另一个命名空间中,你需要明确告诉Python。

main.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 

#... 

其他模块:

import some_helper_module 

db = some_helper_module.db_util.connect() # or whatever the real API is 

#... 

请注意,您通常不能使用你的主模块(这是一个脚本执行)作为共享命名空间。这是因为Python使用模块的__name__属性来确定如何缓存模块(以便始终从多个导入中获取相同的对象),但脚本总是被赋予的"__main__"而不是其真实名称。如果另一个模块导入main,他们将获得单独的(重复)副本!

+0

我在导入后立即在上面的test_scope.py脚本中添加了'cb.ca = ca',认为这会将ca添加到cb名称空间。我仍然没有定义全局,当我从ClassC打印全局变量时,它会打印全局变量:['self'] - 没有对ca的引用,错误仍然存​​在。我错过了什么? – cswaim 2013-05-02 22:30:58

+0

我错过了ca必须被引用为self.ca,因为ca现在在类中定义。 – cswaim 2013-05-03 17:47:54

2

您用错误的观点来解决问题。每个模块是一个启动空的,充满了名字命名空间(典型值)的每个语句运行:

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 

看着ClassX.py我们看到这个名字ca没有这个模块中定义的,但ClassAClassC是。所以从ClassX.py执行行xa=ca()失败。

一般来说,这个想法是每个模块都会导入它所需要的东西。你也可以从外部将一个名称“修改”为一个模块,但这通常被认为是非常糟糕的样式(为非常特殊的情况保留)。