Python:为什么isinstance应该返回True,但实际上可能会返回False?

27

我目前正在使用pdb追踪来解决这个问题

ipdb> isinstance(var, Type)
False
ipdb> type(var)
<class 'module.Type'>
ipdb> Type
<class 'module.Type'>
为什么会发生这种情况?
附注:isinstance(var, type(var)) 返回预期的 True

5
可能会有多种被称为“Type”的类型(例如在不同的时间点)。您能否提供一个完整的示例,以展示这个问题? - NPE
15
你的代码中有任何import/reload的特殊操作吗? - Roman Bodnarchuk
@RomanBodnarchuk,我不这么认为。你能提供一些这样神奇的例子吗? - evgeniuz
@Shark http://docs.python.org/library/functions.html#reload - Roman Bodnarchuk
@RomanBodnarchuk 不,我的源代码中绝对没有 reload 语句。 - evgeniuz
8
我今天遇到了同样的问题,它涉及到绝对导入和相对导入。你可以尝试使用print repr(var.__class__), repr(Type)来检查。我通过将相对导入改为绝对导入来解决了这个问题。我会创建一个演示该问题的代码。 - Kenji Noguchi
3个回答

29
  1. 我只能猜测,但如果你在module中执行...

class Type(object): pass
var = Type()
class Type(object): pass

那么这两种类型看起来都像 <class 'module.Type'>,但它们仍然是不同的。

您可以通过以下方式进行确认

print(id(Type), id(var.__class__))
或使用
print(Type is var.__class__)

请注意,这些比较适用于旧式和新式类。 对于新式类,它们等价于print(Type is type(var))。 但对于旧式类不是这种情况。

  • 另一个非常常见的陷阱是您调用此模块时使用

    python -m module
    
    或者
    python module.py
    

    它被称为__main__模块。如果在其他地方以真实名称导入,则使用不同的命名空间也可以使用该名称。

  • 另一个猜测可能是您正在使用ABCs或使类具有__instancecheck__()方法。


  • 我在所有源文件中只定义了一个类型。而且我没有操纵隐藏的方法,只有__str____iter____len__。所以这不是问题所在。此外,这个类是object的子类。 - evgeniuz
    顺便说一下,我目前在pdb会话中。我应该检查什么来确定原因? - evgeniuz
    你可以考虑查看 id(type(var))type(var) is Type 等内容。 - Karl Knechtel
    对于旧式类,请比较 Type is var.__class__,因为 Type is type(var) 可能会失败。这仍然是相关的,因为 distutils 类被 setuptools 打了猴子补丁。 - 0 _
    #2 对我有帮助。将“from module.sub_module.thing import SpecificThing”更改为“import module.sub_module.thing as thing”,然后在代码中引用“thing.SpecificThing”,问题就解决了。即使我正在使用如下所述的IPython autoreload,这个问题也被解决了。 - Connor Ferster

    15

    "autoreload"设置在iPython中的用户可能会遇到这个问题。当一个类被重新加载时,它将成为一个具有完全相同名称的新类。旧类的实例不会更新其类型:

    # After reloading the Role class
    
    [ins] In [19]: y = Role()
    
    [ins] In [20]: isinstance(x, Role)
    Out[20]: False
    
    [nav] In [21]: isinstance(y, Role)
    Out[21]: True
    
    [ins] In [22]: type(x)
    Out[22]: myproject.auth.Role
    
    [ins] In [23]: type(y)
    Out[23]: myproject.auth.Role
    

    1
    除了 imp.reload(module) 和重新实例化 x 之外,还有其他选项吗?我可以提出一个问题。 - OverLordGoldDragon
    当我使用importlib.reload的顺序错误时,我遇到了这个问题:库1调用了库2,但是我先对库1进行了importlib.reload,然后才是库2,所以每个isinstance都失败了。 - MCK
    1
    @Hubro,你救了我的命。我刚遇到这个问题,找了一个多小时才找到你的解决方案。 - FredMaster

    1

    我也遇到了这个问题,对我来说问题出在我的导入上。我从parent.child.Typechild.Type两次导入了Type。我猜想当使用完整路径时,模块是从已安装的pip包中导入的,而使用相对路径时,它会作为一个新模块即时导入。


    2
    你的回答可以通过提供更多支持信息来改进。请编辑以添加进一步的细节,例如引用或文档,以便他人可以确认你的答案是正确的。您可以在帮助中心中找到有关如何编写良好答案的更多信息。 - Community

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接