| layout | default |
|---|---|
| title | Pythonic Python |
| parent | Lessons |
| nav_order | 1 |
| permalink | /lessons/pythonic-python/ |
| course_lesson | true |
| course_index | 01 |
| previous_page | /setup/ |
| previous_title | Setup |
| next_page | /lessons/advanced-functions/ |
| next_title | Advanced Functions |
Pythonic code uses Python's strengths while remaining easy for another person to read. It does not mean writing the shortest possible code.
Imagine two students solving the same maths problem. One writes many repeated steps. The other notices a clear pattern and explains it in one readable line. Pythonic code is like the second solution: it uses familiar Python tools to express the idea directly.
Always choose clarity first. A five-line loop is better than a one-line expression that nobody understands.
Suppose we want the square of every number. The ordinary loop is:
squares = []
for number in range(1, 6):
squares.append(number * number)
print(squares)Output:
[1, 4, 9, 16, 25]
A list comprehension expresses the same pattern in one line:
squares = [number * number for number in range(1, 6)]
print(squares)Read it from left to right:
result expression loop variable source
number * number for number in range(1, 6)
Add a condition at the end when only some items should be kept:
even_numbers = [number for number in range(10) if number % 2 == 0]
print(even_numbers)The condition is tested for every number. Only numbers that make the condition True enter the new list.
The surrounding brackets decide the result type:
unique_lengths = {len(word) for word in ["cat", "tiger", "dog"]}
squares_by_number = {number: number ** 2 for number in range(1, 4)}
print(unique_lengths)
print(squares_by_number)Output (set order may vary):
{3, 5}
{1: 1, 2: 4, 3: 9}
Important:
{value for value in items}creates a set, but{key: value for ...}creates a dictionary.
Do not put several loops, conditions, and complex calculations into one comprehension. Write a normal loop when the intent stops being obvious.
Unpacking places items from a collection into separate names:
point = (12, 8)
x, y = point
print(x)
print(y)The number of names must normally match the number of items. A starred name gathers the extra items into a list:
first, *middle, last = [10, 20, 30, 40, 50]
print(first)
print(middle)
print(last)Output:
10
[20, 30, 40]
50
Python also makes swapping values safe and clear:
left = "red"
right = "blue"
left, right = right, leftUse enumerate() when a loop needs both an item and its position:
for index, name in enumerate(["Asha", "Ravi"], start=1):
print(index, name)start=1 changes the displayed position. It does not change the list.
names = ["Asha", "Ravi"]
marks = [80, 92]
for name, mark in zip(names, marks):
print(f"{name}: {mark}")By default, zip() stops when the shortest input ends. Use strict=True when different lengths should be treated as a mistake:
names = ["Asha", "Ravi"]
marks = [80]
# list(zip(names, marks, strict=True)) # raises ValueErrormarks = [72, 41, 88]
someone_failed = any(mark < 50 for mark in marks)
everyone_passed = all(mark >= 40 for mark in marks)
print(someone_failed)
print(everyone_passed)any() is True when at least one value is true. all() is True only when every value is true.
Important empty-input rule:
any([])isFalse, whileall([])isTrue. There is no failing item in an empty collection.
sorted() returns a new list. The original collection is not changed:
students = [{"name": "Ravi", "mark": 92}, {"name": "Asha", "mark": 86}]
ranked = sorted(students, key=lambda student: student["mark"], reverse=True)
print(ranked)The key function tells Python which value controls the ordering. Python calls it once for each item.
Use .sort() only when changing the existing list is intentional:
numbers = [3, 1, 2]
result = numbers.sort()
print(numbers)
print(result)Output:
[1, 2, 3]
None
Important:
list.sort()changes the list and returnsNone.sorted(...)returns a new list.
Common Pythonic choices include:
- loop directly over items instead of repeatedly using indexes;
- use
enumerate()when the index is genuinely needed; - use
zip()for related collections; - use
infor membership; - use
dict.get()when a missing key has a sensible default; - use a comprehension for one clear transformation or filter;
- use a normal loop for several steps or side effects.
Find the problem before opening the fix.
numbers = [3, 1, 2]
numbers = numbers.sort()
print(numbers)names = ["Asha", "Ravi", "Meena"]
marks = [80, 92]
for name, mark in zip(names, marks):
print(name, mark)result = [n * 2 if n % 2 == 0 else n * 3 for n in range(20) if n > 4]Show Bug Hunter fixes
- Keep the list name and call
numbers.sort(), or writenumbers = sorted(numbers). - Use
zip(names, marks, strict=True)when unequal lengths are invalid. - Split the logic into a normal loop with named intermediate values when the rule needs explanation.
- Rewrite a loop as a list comprehension.
- Create a dictionary comprehension of numbers and squares.
- Use
enumerate()to number a shopping list. - Use
zip()to combine names and scores. - Find whether any score is below 40 with
any(). - Find whether all scores are passing with
all(). - Sort records by a nested value.
- Unpack a tuple containing a date.
- Flatten a two-level list with a comprehension.
- Refactor a small repetitive script into Pythonic functions.
Show hints
- Put the expression before
for. - Use
{number: number ** 2 for number in values}. - Start
enumerate()at 1. - Keep the sequences the same length.
any(condition for item in items).all(condition for item in items).- Use
key=lambda record: .... - Match one name to each tuple value.
- Use two
forclauses. - Remove repeated logic but do not make a clever one-liner.
Show solution ideas
[value * 2 for value in values].{number: number ** 2 for number in range(1, 6)}.for position, item in enumerate(items, start=1).for name, score in zip(names, scores).any(score < 40 for score in scores).all(score >= 40 for score in scores).sorted(records, key=lambda record: record["score"]).year, month, day = date.[item for row in rows for item in row].- Extract a function with named inputs and a clear return value.
Build a student report using comprehensions, enumerate(), zip(), sorting, and any()/all().
Explain when a comprehension improves code and when a normal loop is clearer.