python bool()和__bool__

最近在学习python ,做个记录以免忘记,也把笔记分享出来,供大家参考。

    当我们要判断一个值的真假时,往往使用bool(object)方法, 它会判断对象(object)的真假,并返回True或False。但是一直没明白为什么可以直接用bool()或者len()方法。

    原来bool(object), 其实背后是调用的object.__bool__方法的结果,如果该对象不存在__bool__方法,则python会调用__len__方法。如果返回0则bool()返回False,否则返回True。默认情况下我们自定义的类的实例会被认为是真的,除非自定义的类的__bool__和__len__方法有其他实现。

>>> a = 0
>>> dir(a)
['__abs__', '__add__', '__and__', '__bool__', '__ceil__', '__class__', '__delattr__', '__dir__', '__divmod__', '__doc__', '__eq__', '__float__', '__floor__', '__floordiv__', '__format__', '__ge__', '__getattribute__', '__getnewargs__', '__gt__', '__hash__', '__index__', '__init__', '__init_subclass__', '__int__', '__invert__', '__le__', '__lshift__', '__lt__', '__mod__', '__mul__', '__ne__', '__neg__', '__new__', '__or__', '__pos__', '__pow__', '__radd__', '__rand__', '__rdivmod__', '__reduce__', '__reduce_ex__', '__repr__', '__rfloordiv__', '__rlshift__', '__rmod__', '__rmul__', '__ror__', '__round__', '__rpow__', '__rrshift__', '__rshift__', '__rsub__', '__rtruediv__', '__rxor__', '__setattr__', '__sizeof__', '__str__', '__sub__', '__subclasshook__', '__truediv__', '__trunc__', '__xor__', 'bit_length', 'conjugate', 'denominator', 'from_bytes', 'imag', 'numerator', 'real', 'to_bytes']
>>>
这里看到我们在创建a变量时,因为a此时是int类的实例,int类有__bool__方法。所以如果此时调用bool(a),则实际使用的是a的__bool__内建方法。
>>> bool(a)
False
>>>
而如果a是str呢?

>>> a = 'test'
>>> dir(a)
['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmod__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'capitalize', 'casefold', 'center', 'count', 'encode', 'endswith', 'expandtabs', 'find', 'format', 'format_map', 'index', 'isalnum', 'isalpha', 'isdecimal', 'isdigit', 'isidentifier', 'islower', 'isnumeric', 'isprintable', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'maketrans', 'partition', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill']
>>>
此时a是str类的实例,str类没有__bool__内建方法,则python会调用__len__方法,如果返回0则bool()返回False,否则返回True。

>>> bool(a)
True
>>>
上面因为a的len不为0,所以返回True。我们将a定义为空字符串试试:
>>> a = ''
>>> bool(a)
False
>>>
可以看到由于a的长度为0 ,所以bool()返回False。当a长度不为0时,看到的结果就是True:

>>> a = 'test'
>>> bool(a)
True
>>>

我们自定义一个类来试试。

>>> class A():
...     pass
...
>>> a = A()
>>> bool(a)
True
>>>
得到的结果为True,因为我们没有自定义__bool__或__len__。默认情况下自定义的类的实例总是被认为是真的True。
我们自定义一下A的__bool__方法:

>>> class A():
...     def __bool__(self):
...             return False
...
>>> b = A()
>>> bool(b)
False
>>>
再来自定义一下__len__方法:

>>> class A():
...     def __len__(self):
...             pass
...
>>> a = A()
>>> bool(a)
Traceback (most recent call last):
  File "", line 1, in 
TypeError: 'NoneType' object cannot be interpreted as an integer
>>> len(a)
Traceback (most recent call last):
  File "", line 1, in 
TypeError: 'NoneType' object cannot be interpreted as an integer
>>>
显然现在bool()方法对于a来说就无效了。因为我们定义的__len__方法返回了一个pass。

而此时我们使用if语句来看看:

>>> if a:
...     print('2222')
...
Traceback (most recent call last):
  File "", line 1, in 
TypeError: 'NoneType' object cannot be interpreted as an integer
>>>
发现if语句无法判断a,因为初学所以我猜测在运行if 语句时,python自动调用了a的内部方法(后面再研究)。同时bool()和len()都无法使用了。所以如果自定义的类,既需要自定义__bool__或__len__又要支持bool()和len()方法,那就要合理的定义这两个方法了,否则会报错的。







你可能感兴趣的:(python)