Python命名空间:__main__.Class 不是 package.Class 的实例

7 投票
3 回答
5736 浏览
提问于 2025-04-17 17:35

假设你有两个Python文件,分别如下。一个是通用的包(class2),另一个是做特定覆盖并作为可执行文件的(class1)。

class1.py:

#!/usr/bin/python
class Test(object):
    pass

class Verificator():
    def check(self, myObject):
        if not isinstance( myObject, Test ):
            print "%s is no instance of %s" % (type(myObject),Test)
        else:
            print "OK!"

if __name__ == '__main__':
    from class2 import getTest

    v = Verificator()
    t = Test()
    v.check(t)
    s = getTest()
    v.check(s)

class2.py:

from class1 import Test
def getTest():
    return Test()

发生的情况是,第一个检查通过了,但第二个检查失败了。原因是t__main__.Test,而sclass1.Test,而v.check()检查的是__main__.Test,但说到底,它们其实是同一个类,对吧?

有没有办法让v.check()也能接受class1.Test对象,或者有什么其他方法可以解决这个问题?

3 个回答

-2

你可以使用 type() 这个函数(其实你会发现这个用法很常见!):

#!/usr/bin/python
class Test(object):
    pass

class Verificator():
    def check(self, myObject):
        if not isinstance( type(myObject), type(Test) ):
            print "%s is no instance of %s" % (type(myObject),Test)
        else:
            print "OK!"

if __name__ == '__main__':
    from class2 import getTest

    v = Verificator()
    t = Test()
    v.check(t)
    s = getTest()
    v.check(s)

可能更糟糕的解决方案是:

if not isinstance( myObject.__class__, Test.__class__ ):  # Use __class__ here.

这两者其实是等价的,但一般来说,除非你真的很需要,不然不建议使用双下划线的成员!不过知道它们的存在还是有必要的,所以我在这里提到它。

需要注意的是,按照我所了解的,当你运行 python class1.py 时,class1.py 是没有模块的。因此,python 会把所有东西放到 __main__ 模块里。这种情况在你从其他脚本导入时就不一样了,所以看到某些东西作为 __main__ 模块的一部分其实是个特殊情况!

1

感谢你的提示,这些提示最终帮助我朝着正确的方向进行实验。我在这个简单模型中找到的解决办法是通过导入来解决命名空间的问题。为了排除用户4815162342提到的问题,我在class1中添加了另一个类。下面是class1.py的代码,看起来可以实现我想要的效果:

#!/usr/bin/python
class Test(object):
    pass

class Toast(object):
    pass

class Verificator():
    def check(self, myObject):
        if not isinstance( myObject, Test ):
            print "NOPE: %s is no instance of %s" % (type(myObject),Test)
        else:
            print "OK: %s is instance of %s" % (type(myObject),Test)

if __name__ == '__main__':
    from class2 import getTest
    from class1 import Test, Toast

    v = Verificator()
    t = Test()
    v.check(t)
    t = getTest()
    v.check(t)
    t = Toast()
    v.check(t)
8

如果你打算从其他地方导入 class1.py,那么最好把最上面的代码(if __name__ == '__main__': ...)放到一个单独的文件里。这样的话,主文件和 class2 就可以共享同一个 class1.Test 类。

如果不这样做,就会引发很多麻烦。虽然你可以通过把 isinstance 换成 type(myObject).__name__ == ... 来暂时解决问题,但实际上你的 Python 程序里会有两个 Test 类,而应该只有一个。这两个类看起来一模一样,但彼此之间并不知道对方的存在,因此在进行 issubclass 测试时会失败。这几乎可以保证后面会出现难以排查的错误。

编辑
另一种选择是在作为主程序执行时,明确从 class1 导入类,就像你在回答中提到的那样。更进一步,建议确保这些类不会被重复定义。比如,你可以把 if __name__ == '__main__' 这段代码放到文件的开头,并以 sys.exit(0) 结束:

if __name__ == '__main__':
    import class1, class2
    ... use only the public API with module prefixes ...
    sys.exit(0)

# the rest of the module follows here

撰写回答