Lesson 4 · Python data types deep dive
Python Booleans & None Explained: Truthy vs Falsy | Data Types #4
Video four of the twelve-part series: bool and None, two small types with outsized influence on how every if statement, loop, and comparison in Python…
- CoursePython data types deep dive
- Lesson4 of 12
- Video23 min
- FormatJupyter notebook · 19 code cells
What you'll learn
Data
No separate download needed — the notebook creates or downloads everything it uses.
📓 Full notebook
Download .ipynbPython Data Types Deep-Dive, Video 4: Booleans and None (bool, NoneType)#
- Video four of the twelve-part series: bool and None, two small types with outsized influence on how every if statement, loop, and comparison in Python actually behaves.
- Truthiness rules for every other type, short-circuit evaluation, and the real difference between is and ==.
- Let's get into it.
Part 1: bool Is a Subclass of int#
print(type(True))
print(isinstance(True, int))
print(issubclass(bool, int))
print(True == 1)
print(False == 0)
print(True + True)
print(True * 5)
Part 2: Truthy and Falsy Values#
falsy_values = [False, None, 0, 0.0, 0j, '', [], (), {}, set(), range(0)]
for value in falsy_values:
print(f'{value!r} is falsy: {not bool(value)}')
truthy_examples = [True, 1, -1, 0.1, 'False', ' ', [0], (0,), {'a': 1}]
for value in truthy_examples:
print(f'{value!r} is truthy: {bool(value)}')
Part 3: The bool() Constructor#
print(bool(42))
print(bool(0))
print(bool('hello'))
print(bool(''))
print(bool([1, 2, 3]))
print(bool(None))
print(bool(bool))
Part 4: Comparison Operators Return bool#
is_adult = 25 >= 18
print(is_adult)
print(type(is_adult))
has_items = 3 in [1, 2, 3, 4]
print(has_items)
is_same_object = [] is []
print(is_same_object)
Part 5: Boolean Operators and Short-Circuit Evaluation#
print(3 and 5)
print(0 and 5)
print(3 or 5)
print(0 or 5)
print(not 3)
print(not 0)
def expensive_check():
print('expensive_check actually ran')
return True
print('--- with False and ---')
result = False and expensive_check()
print('--- with True or ---')
result = True or expensive_check()
Part 6: The Common x or default Idiom#
def greet(name=None):
display_name = name or 'friend'
return f'Hello, {display_name}!'
print(greet('Ana'))
print(greet())
print(greet(''))
Part 7: Inherited int Methods on bool#
print(True.bit_length())
print(False.bit_length())
print(True.bit_count())
print(True.to_bytes(1, byteorder='big'))
print(True.as_integer_ratio())
print(True.numerator, True.denominator)
print(True.real, True.imag)
print(True.conjugate())
Part 8: Counting With sum() on Booleans#
scores = [45, 78, 92, 61, 88, 34, 95]
passing = [score >= 60 for score in scores]
print(passing)
print(sum(passing))
print(f'{sum(passing)} out of {len(scores)} passed')
Part 9: None, the Absence of a Value#
value = None
print(value)
print(type(value))
print(type(None))
another_none = None
print(value is another_none)
Part 10: is None Versus == None#
class WeirdEquality:
def __eq__(self, other):
return True
weird = WeirdEquality()
print(weird == None)
print(weird is None)
import warnings
with warnings.catch_warnings(record=True) as caught:
warnings.simplefilter('always')
exec('result = (5 == None)')
print(result)
print(len(caught) >= 0)
Part 11: The Mutable Default Argument Pitfall#
def broken_add_item(item, target_list=[]):
target_list.append(item)
return target_list
print(broken_add_item('a'))
print(broken_add_item('b'))
def fixed_add_item(item, target_list=None):
if target_list is None:
target_list = []
target_list.append(item)
return target_list
print(fixed_add_item('a'))
print(fixed_add_item('b'))
Part 12: None in Conditions and Function Return Values#
def no_explicit_return(x):
print(f'Processing {x}')
result = no_explicit_return(5)
print(result)
print(result is None)
def find_first_negative(numbers):
for n in numbers:
if n < 0:
return n
return None
result = find_first_negative([3, 7, -2, 9])
if result is not None:
print(f'Found: {result}')
else:
print('No negative number found')
Part 13: Common Patterns and Pitfalls#
ages = [22, 35, 41, 19, 28]
print(all(age >= 18 for age in ages))
print(any(age >= 40 for age in ages))
print(all([]))
print(any([]))
flag = True
if flag:
print('Correct idiom: works for any truthy value')
if flag is True:
print('Fragile idiom: fails silently for truthy non-bool values like 1')
flag_as_int = 1
print(flag_as_int is True)
Wrap-Up: What You Learned#
- bool is a genuine subclass of int, with True as one and False as zero in every arithmetic context.
- The complete, exhaustive list of falsy values, and how bool() applies those rules explicitly.
- Comparison operators all return real bool values.
- Short-circuit evaluation: and and or return an actual operand, not just True or False, enabling the x-or-default idiom.
- Every inherited int method still technically works on bool.
- Counting truthy conditions with sum(), and checking whole collections with all() and any().
- None: the one-and-only NoneType singleton, why is None beats == None, the mutable default argument pitfall, and implicit None returns.
- Next up: str, the largest built-in type in this series, with all forty-seven of its methods covered one at a time.
Found this useful?
All lessons, notebooks and datasets here are free. If they helped you, a coffee keeps new lessons coming.



