使用 isinstance 比较布尔值和整数

90

有人能解释一下为什么在下面的情况下 isinstance() 返回 True 吗?当我编写代码时,我期望的是 False。

print isinstance(True, (float, int))
True

我猜可能是Python的内部子类化,因为无论是float还是int的零和一在用作布尔值时都会被评估,但不知道确切的原因。

解决这种情况最pythonic的方法是什么?我可以使用type(),但在大多数情况下,这被认为不够pythonic。

6个回答

130
由于历史原因,boolint的子类,因此Trueint的一个实例。(最初,Python没有bool类型,返回真值的东西返回1或0。当他们添加了bool时,为了向后兼容尽可能地替换1和0,True和False必须成为插入式替换,因此进行了子类化。)
“解决”这个问题的正确方法取决于您认为问题是什么。
  • If you want True to stop being an int, well, too bad. That's not going to happen.
  • If you want to detect booleans and handle them differently from other ints, you can do that:

    if isinstance(whatever, bool):
        # special handling
    elif isinstance(whatever, (float, int)):
        # other handling
    
  • If you want to detect objects whose specific class is exactly float or int, rejecting subclasses, you can do that:

    if type(whatever) in (float, int):
        # Do stuff.
    
  • If you want to detect all floats and ints, you're already doing that.

1
这是第二种情况。这意味着必须注意这些内置类型比较的顺序 - 这在继承方面是可以理解的,但对于Python来说相当不寻常。 - jake77
4
“真”和“假”是类“int”的单例实例。print(True.real)是1,而print(False.real)是0。 print(True == 1)为真,并且print(False == 0)也为真。所以如果你希望参数是整数类型,但用户却传入了布尔类型,那么一个isinstance(param, int)的检查将会“恼人地”对他们传递的值返回真,因为布尔型本质上是一种整数类型...但这不会有太大的影响,因为它就像是传递了 param = 1 或者 param = 0。因此,您仍然可以对其进行数值运算,因为布尔值在内部实际上是一种“整数”类型。 - Mitch McMabers
5
更深入的解释第二部分:你甚至可以执行print(True + 3),它会输出4(1 + 3),以及print(False + 3),它会输出3(0 + 3)。呵呵。但是正如上面的答案所指出的那样,如果你想要100%确定参数是一个int而不是一个bool,你只需要检查if type(param) is int,因为这不会接受任何子类。(只要注意一下,如果你的API用户可能会传递他们自己从int派生的自定义对象作为基类,例如如果他们制作了一个带有一些额外方法的数字类,该类是一个int...那么他们的子类也将被这样严格的检查拒绝...) - Mitch McMabers

10

您可以查看方法解析顺序,并从中找到所有的超类:

>>> bool.__mro__
(<class 'bool'>, <class 'int'>, <class 'object'>)

8

是的,没错,它是 int 的子类,您可以使用解释器进行验证:

>>> int.__subclasses__()
[<type 'bool'>]

5
如果您只想检查int
if type(some_var) is int:
    return True

else:
    return False

更简单的写法:return isinstance(some_var, int) - wjandrea

0

了解一些关于 Python 中布尔值和整数的行为(并不那么奇怪)

>>> 1 == True  
True           
>>> 0 == False 
True           
>>> True*5 == 0
False          
>>> True*5 == 5
True           
>>> 

它们可以互换使用到什么程度...!

从 boolobject.h(win py 2.7)中,我可以看到将 int 定义为 bool obj 的 typedef。因此,很明显 bool 继承了 int 的一些面部特征。

#ifndef Py_BOOLOBJECT_H
#define Py_BOOLOBJECT_H
#ifdef __cplusplus
extern "C" {
#endif


typedef PyIntObject PyBoolObject;

0

这里有一个实例检查器,它对布尔型数据是安全的,而且可以像isinstance()一样接受单个类型或类型的元组。

def isInst(o, of) -> bool:
    if o is None: return False
    cls = o.__class__
    if isinstance(of, type):
        return cls == of

    else:
        if cls == bool:
            return bool in of
        else:
            for i in range(len(of)):
                if cls == of[i]: return True

    return False

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