未定义Python作为全局名称导入

2024-05-23 13:31:36 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个在Postgres&Mysql上运行的应用程序。每个程序检查以确定数据库,然后将postgres_db作为db_util或mysql_dt作为db_util导入。当main中的代码引用db_util时,所有这些都可以正常工作,但如果导入了类,则不会定义对db_util的引用。

我创建了下面的类和main来测试这个问题,并发现了另一个有趣的副作用。B&C类参考不同进口情况下的A类。B&C是相同的,只是B在主控和C是进口的。

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

测试范围.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(imported as)对ClassC不可用,但是模块ClassA可用(不带as导入)。

  1. 为什么导入和导入作为行为的区别?我不清楚为什么主要的全球不提供类主要进口。
  2. 动态确定要导入的合适的db_util模块并让其他导入的类可以访问它的好方法是什么?

更新: 在阅读了另一篇关于名称空间的文章:“Visibility of global variables from imported modules”之后,我理解在上面的示例中,classA对ClassC可用的原因是:A&C位于同一个导入的文件中,因此是同一个名称空间。

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

如果我有这样的代码:

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

如何使db_util对所有导入的模块都可用?

更新:

根据Blckknght的回复,我添加了代码

cb.ca =ca

作用域测试脚本。这要求将对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#为适当的数据库选择类的新模块

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来导入它,但它确实会使依赖关系为人所知。

我将结束这一问题,并要感谢布莱克克特和阿米恩里戈他们的回答,帮助我澄清这个问题。我会感谢任何与设计相关的反馈。


Tags: 模块fromimportrefdbutilclassca
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()行失败。

一般来说,其思想是每个模块都导入它所需要的内容。您也可以从外部将名称“插入”模块,但这通常被认为是非常糟糕的样式(为非常特殊的情况保留)。

在Python中,每个模块都有自己的全局命名空间。进行导入时,只需将导入的模块添加到当前模块的命名空间中,而不是添加到任何其他模块的命名空间中。如果要将它放在另一个名称空间中,需要显式地告诉Python这一点。

主.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__属性来确定如何缓存该模块(以便始终从多个导入中获取相同的对象),但脚本总是被赋予__name__"__main__"而不是其真实名称。如果另一个模块导入main,它们将得到一个单独(重复)的副本!

相关问题 更多 >