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 "<stdin>", line 1, in <module>
TypeError: 'NoneType' object cannot be interpreted as an integer
>>> len(a)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'NoneType' object cannot be interpreted as an integer
>>>
顯然現在bool()方法對於a來說就無效了。因爲我們定義的__len__方法返回了一個pass。

而此時我們使用if語句來看看:

>>> if a:
...     print('2222')
...
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'NoneType' object cannot be interpreted as an integer
>>>
發現if語句無法判斷a,因爲初學所以我猜測在運行if 語句時,python自動調用了a的內部方法(後面再研究)。同時bool()和len()都無法使用了。所以如果自定義的類,既需要自定義__bool__或__len__又要支持bool()和len()方法,那就要合理的定義這兩個方法了,否則會報錯的。







發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章