csw*_*aim 3 python import global python-import
我有一个在Postgres和Mysql上运行的应用程序.每个程序检查以确定数据库,然后将postgres_db作为db_util或mysql_dt导入为db_util.当主引用db_util中的代码时,一切正常,但如果导入了类,则不会定义对db_util的引用.
我创建了以下类和main来测试问题,并发现了另一个有趣的副作用.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()
Run Code Online (Sandbox Code Playgroud)
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()
Run Code Online (Sandbox Code Playgroud)
结果如下:
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 . . .
Run Code Online (Sandbox Code Playgroud)
从我的测试中,我看到对象ca(导入为)不可用于ClassC,但是,模块ClassA可用(导入时没有).
更新: 在阅读了关于命名空间的另一篇文章:" 导入模块中全局变量的可见性 "之后,我理解在上面的示例中,ClassA可用于ClassC的原因是A&C在同一导入文件中,因此具有相同的命名空间.
所以剩下的问题是一个设计问题:
如果我有这样的代码:
if db == 'MySQL':
from mysql_db import db_util
elif db == 'Postgres'
from postgres_db import db_util
Run Code Online (Sandbox Code Playgroud)
使db_util可用于所有导入模块的好方法是什么?
更新:
从Blckknght的回应中,我添加了代码
cb.ca =ca
Run Code Online (Sandbox Code Playgroud)
到scope_test脚本.这需要将对xa = ca()的类调用更改为xa = self.ca().我还认为,尽管Python允许,但是从类外部向类中添加对象并不是一种好的设计方法,并且会使调试成为一场噩梦.
但是,因为我认为模块和类应该是独立的或者专门声明它们的依赖关系,所以我将使用上面的代码示例来实现这样的类.
将ClassA和ClassC分解为单独的模块,并在ClassC的顶部,在类定义之前进行导入
from ClassA import ClassA
from ClassA import ClassA as ca
class ClassB(object):
Run Code Online (Sandbox Code Playgroud)
在我的实际情况中,我需要将db_util模块导入几个模块
ci.py #new模块为适当的db选择类
if db == 'MySQL':
from mysql_db import db_util
elif db == 'Postgres'
from postgres_db import db_util
Run Code Online (Sandbox Code Playgroud)
在需要db_util类的每个模块中
import ci
db_util=ci.db_util #add db_util to module globals
class Module(object):
Run Code Online (Sandbox Code Playgroud)
这样做的一个问题是它需要每个模块使用db_util来导入它,但它确实使依赖性已知.
我将结束这个问题,并感谢Blckknght和Armin Rigo的回复,这些回复有助于我澄清这个问题.我很感激任何与设计相关的反馈.
在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
#...
Run Code Online (Sandbox Code Playgroud)
其他模块:
import some_helper_module
db = some_helper_module.db_util.connect() # or whatever the real API is
#...
Run Code Online (Sandbox Code Playgroud)
请注意,您通常不能将主模块(作为脚本执行)用作共享命名空间.这是因为Python使用模块的__name__
属性来确定如何缓存模块(让你始终得到多次导入同一个对象),但脚本总是给出__name__
的"__main__"
,而不是它的真实姓名.如果另一个模块导入main
,他们将获得一个单独的(重复)副本!
归档时间: |
|
查看次数: |
21670 次 |
最近记录: |