For AI agents: use /llms.txt for the Nakafa content index.
In Python, an iterable is an object that can produce one item at a time for a loop or another consumer. Strings, lists, tuples, sets, dictionaries, files, and generators are all iterable even though they organize and produce items differently.
An iterable does not have to be ordered, indexable, reusable, or finite. Its defining promise is narrower: iter() can obtain an iterator that supplies items until it is exhausted.
Python provides various types of iterables that you commonly use in everyday programming.
# String as iterable
text = "hello"
print("Characters in string:")
for char in text:
print(char)
# Output:
# Characters in string:
# h
# e
# l
# l
# o
print()
# List as iterable
numbers = [1, 2, 3, 4, 5]
print("Elements in list:")
for num in numbers:
print(num)
# Output:
# Elements in list:
# 1
# 2
# 3
# 4
# 5
print()
# Tuple as iterable
coordinates = (10, 20, 30)
print("Elements in tuple:")
for coord in coordinates:
print(coord)
# Output:
# Elements in tuple:
# 10
# 20
# 30The string yields characters in text order. Lists and tuples yield their stored elements in position order. Other iterable types may follow different ordering rules.
The operators in and not in ask whether a container contains a value. The exact membership rule belongs to the container type.
Built-in sequences search their items until they find a match or reach the end. Sets and dictionaries use their own lookup behavior, and dictionary membership checks keys rather than values.
# Membership checking in list
fruits = ["apple", "orange", "mango"]
# Using in operator
if "apple" in fruits:
print("Apple is available in the fruit list")
# Output: Apple is available in the fruit list
# Using not in operator
if "durian" not in fruits:
print("Durian is not available in the fruit list")
# Output: Durian is not available in the fruit list
print()
# Membership checking in string
message = "Python is a programming language"
# Searching substring in string
if "Python" in message:
print("Python word found in message")
# Output: Python word found in message
if "Java" not in message:
print("Java word not found in message")
# Output: Java word not found in messageFor strings, the left operand may be a single character or a longer substring. The test is case-sensitive and checks for one contiguous occurrence.
# Character checking in string
text = "programming"
# Searching single character
print("g" in text) # Output: True
print("z" in text) # Output: False
print()
# Searching substring in string
print("gram" in text) # Output: True
print("program" in text) # Output: True
print("java" in text) # Output: False
# Marker check only, not full email validation
email = "user@example.com"
if "@" in email and ".com" in email:
print("Contains basic email markers")
# Output: Contains basic email markersThe final check only demonstrates two markers. It is not sufficient email validation because many invalid addresses contain both @ and .com, while many valid addresses use another domain suffix.
The built-ins any() and all() consume an iterable and test the truthiness of its items. Both stop as soon as the result is known, so generator expressions avoid building an unnecessary intermediate list.
any() returns True after the first truthy item. It returns False only when every item is falsy or the iterable is empty.
# Example using any()
grades = [60, 75, 45, 80]
# Check if there are values above 70
print("High grades exist:", any(grade > 70 for grade in grades))
# Output: High grades exist: True
# Example with direct boolean
conditions = [False, False, True, False]
print("True condition exists:", any(conditions))
# Output: True condition exists: True
# Example with empty list
empty_list = []
print("Any on empty list:", any(empty_list))
# Output: Any on empty list: False
# Practical example
numbers = [0, 0, 5, 0]
if any(numbers):
print("Non-zero numbers exist in list")
# Output: Non-zero numbers exist in listall() returns False after the first falsy item. If iteration ends without one, it returns True. This also explains the empty case: there is no item that violates the condition.
# Example using all()
scores = [85, 90, 78, 92]
# Check if all values are above 70
print("All grades pass:", all(score >= 70 for score in scores))
# Output: All grades pass: True
# Example with direct boolean
conditions = [True, True, True, True]
print("All conditions true:", all(conditions))
# Output: All conditions true: True
# Example with one false condition
mixed_conditions = [True, True, False, True]
print("All conditions true:", all(mixed_conditions))
# Output: All conditions true: False
# Practical example
ages = [18, 21, 25, 30]
if all(age >= 18 for age in ages):
print("All participants are adults")
# Output: All participants are adultsIn a function call, a leading asterisk (*) expands an iterable into positional arguments. The resulting argument count must still match what the function accepts.
A function expecting separate coordinates receives a list as one argument unless you unpack it. Manual indexing works for a fixed shape but repeats the container structure at every call site.
import math
# Problem: math.hypot function needs separate arguments
coordinates = [3, 4]
# Wrong way - will result in error
try:
result = math.hypot(coordinates)
print(result)
except TypeError as e:
print("Error:", e)
# Output: Error: must be real number, not list
# Manual way that's troublesome for many arguments
result = math.hypot(coordinates[0], coordinates[1])
print("Manual result:", result)
# Output: Manual result: 5.0
# Example with more arguments
points = [1, 1, 1, 1]
# Manual way becomes very troublesome
result = math.hypot(points[0], points[1], points[2], points[3])
print("Result with 4 arguments:", result)
# Output: Result with 4 arguments: 2.0Placing * before the iterable in the call passes each produced item as its own positional argument.
import math
# Solution with unpacking operator
coordinates = [3, 4]
result = math.hypot(*coordinates)
print("Distance from origin:", result)
# Output: Distance from origin: 5.0
# Example with tuple
point_3d = (1, 2, 2)
distance = math.hypot(*point_3d)
print("3D distance:", distance)
# Output: 3D distance: 3.0
# Example with many arguments
dimensions = [2, 3, 6, 1, 4]
euclidean_distance = math.hypot(*dimensions)
print("Euclidean distance:", euclidean_distance)
# Output: Euclidean distance: 8.12403840463596
# Other practical example
def calculate_average(a, b, c):
return (a + b + c) / 3
grades = [85, 90, 78]
average = calculate_average(*grades)
print("Average grade:", average)
# Output: Average grade: 84.33333333333333The same syntax works in function calls and in collection displays. Use it when expansion is part of the intended interface, not when a function already accepts one iterable directly.
# Unpacking for print function
items = ["apple", "orange", "mango"]
print("Fruits:", *items)
# Output: Fruits: apple orange mango
# Unpacking fixed arguments for range()
bounds = [2, 10, 2]
print("Even values:", list(range(*bounds)))
# Output: Even values: [2, 4, 6, 8]
# Unpacking to combine lists
list1 = [1, 2, 3]
list2 = [4, 5, 6]
combined = [*list1, *list2]
print("Combined list:", combined)
# Output: Combined list: [1, 2, 3, 4, 5, 6]
# Unpacking in string format function
template = "Name: {}, Age: {}, City: {}"
data = ["Alice", 25, "Jakarta"]
formatted = template.format(*data)
print(formatted)
# Output: Name: Alice, Age: 25, City: Jakarta