Truthy/Falsy and is vs ==
After this topic
You will understand how values in Python are evaluated as True/False in conditional statements, and you will be able to correctly distinguish and use is and ==.
Truthy and Falsy
Python's if statement doesn't just accept True/False. Any value can be used as a condition:
if "hello": print("executed!") # Executed!
if 0: print("not executed") # Not executedPython divides all values into Truthy (treated as true) and Falsy (treated as false).
Falsy Values β Just Memorize These
There are a fixed number of Falsy values. Everything else is Truthy:
# These are Falsy (evaluate to False)FalseNone0 # Integer 00.0 # Float 0"" # Empty string[] # Empty list{} # Empty dictionaryset() # Empty set# Let's verifyvalues = [False, None, 0, 0.0, "", [], {}, set()]for v in values: print(f"{str(v):10} β {bool(v)}")# False β False# None β False# 0 β False# 0.0 β False# β False# [] β False# {} β False# set() β FalseKey rule: "Empty or zero is Falsy". Just remember this.
Practical Pattern β Checking for Empty Values
Using Truthy/Falsy makes your code more concise:
# Checking if a list is emptyitems = []
# No need to write thisif len(items) > 0: print("exists")
# Just write thisif items: print("exists")# Checking if a string is emptyname = ""
if name: print(f"Hello, {name}")else: print("Please enter your name")# Checking for None and providing a default valuedef greet(name=None): name = name or "Guest" return f"Hello, {name}"
print(greet()) # "Hello, Guest"print(greet("μ² μ")) # "Hello, μ² μ"The or operator returns the right-hand side if the left-hand side is Falsy. This is often used as a default value pattern.
== β Are the Values Equal?
== compares if two values are equal:
a = [1, 2, 3]b = [1, 2, 3]
print(a == b) # True β because the contents are the sameThe two lists are separate objects, but since the values they contain are the same, == returns True.
print(1 == 1.0) # True β if the numerical values are the sameprint("abc" == "abc") # Trueprint([1] == [1]) # Trueis β Is it the Same Object?
is compares whether two variables point to the same object in memory:
a = [1, 2, 3]b = [1, 2, 3]c = a
print(a == b) # True β values are the sameprint(a is b) # False β different objectsprint(a is c) # True β pointing to the same objecta and b have the same contents but are different list objects. c = a points to the same list, so is is True.
# Can be verified with id()print(id(a)) # 140234567890print(id(b)) # 140234567920 (different address)print(id(c)) # 140234567890 (same address as a)Why You Should Use is for None Comparison
result = None
# β
Correct wayif result is None: print("No result")
# β Not recommendedif result == None: print("No result")None is a single object in all of Python. Comparing with is directly checks if "this is that one None object?".
== can behave unexpectedly if a class overrides the __eq__ method:
class Tricky: def __eq__(self, other): return True # Returns True when compared to anything
t = Tricky()print(t == None) # True β dangerous!print(t is None) # False β safePEP 8 (the official Python style guide) also explicitly states that is should be used for None comparisons.
Integer Caching Trap
a = 256b = 256print(a is b) # True β CPython caches -5 to 256 in advance
a = 257b = 257print(a is b) # False β creates a separate object outside the rangeCPython pre-creates and reuses small integers (-5 to 256). Within this range, is is True, but outside it is False. This is why you shouldn't use is for value comparison. is should only be used for None, True, and False comparisons.
# Similar phenomenon with stringsa = "hello"b = "hello"print(a is b) # True β string interning in effect
a = "hello world!"b = "hello world!"print(a is b) # False β interning does not occur with spaces and special charactersFunction Parameter Default Values and None
# β Dangerous patterndef add_item(item, items=[]): items.append(item) return items
print(add_item("a")) # ["a"]print(add_item("b")) # ["a", "b"] β the result of the previous call remains!
# β
Safe patterndef add_item(item, items=None): if items is None: items = [] items.append(item) return itemsWhen mutable objects (lists, dictionaries) are used as default values, all calls share the same object. Using None as the default value and creating a new object inside the function is the standard Python pattern.
bool() and Utilizing Truthy/Falsy
# Concise empty value checkingdata = {"name": "μ² μ", "email": "", "phone": None}
# β Long and repetitiveif data["name"] is not None and data["name"] != "": print("name exists")
# β
Utilize Truthy/Falsyif data["name"]: print("name exists")
# Filter only valid valuesvalues = [0, "", None, "hello", [], [1, 2], False, 42]valid = list(filter(None, values))print(valid) # ["hello", [1, 2], 42]filter(None, iterable) removes all Falsy values. This is a pattern often used for data cleaning.
Summary
| Comparison | Meaning | When to Use |
|---|---|---|
== | Are the values equal? | General value comparison |
is | Is it the same object? | None, True, False comparison |
!= | Are the values different? | General inequality check |
is not | Is it a different object? | is not None |
# Remember these patternsif x is None: # Check for Noneif x is not None: # Check if not Noneif items: # Is it not empty (Truthy)if not items: # Is it empty (Falsy)any() and all() β Utilizing Truthy in Collections
scores = [85, 92, 0, 78, 95]
print(any(scores)) # True β at least one Truthy value (a value other than 0)print(all(scores)) # False β 0 is Falsy
# Together with conditional expressionsprint(any(s >= 90 for s in scores)) # True β is there a score greater than or equal to 90?print(all(s >= 60 for s in scores)) # False β are all scores greater than or equal to 60?any() and all() internally use Truthy/Falsy evaluation. They are useful for expressing conditions concisely.
Utilizing Short-circuit Evaluation
# or β returns the first Truthy value (or the last value if none)name = user_input or "DefaultName"
# and β returns the first Falsy value (or the last value if none)result = data and data[0] # returns [] if data is empty, otherwise returns the first elementor and and don't just return booleans; they return the value at the point where the Truthy/Falsy evaluation stops. This is often used for setting default values or in safe access patterns.
Not understanding the difference between == and is can lead to hard-to-find bugs. In particular, making it a habit to use is instead of == for None comparisons is fundamental to Python code quality.