For AI agents: use /llms.txt for the Nakafa content index.
Syntactic sugar is a concise notation for behavior that could also be expressed more explicitly. It can remove repetitive ceremony, but shorter syntax is useful only when the reader can still see what the code does.
Python offers several compact forms for common patterns. They do not automatically make a program run faster, and they are not interchangeable in every detail. The goal is clearer intent, not the fewest possible characters.
A list comprehension creates a new list from any iterable. It can transform values, filter them, or combine both operations in one expression.
List comprehension has several syntax forms:
# Basic form
newlist = [expression for item in iterable]
# With condition
newlist = [expression for item in iterable if condition]
# With if-else (conditional expression must appear before for)
newlist = [if_expr if condition else else_expr for item in iterable]Note that in the third form, the if-else expression must appear before the for loop. This is different from the second form where the if condition appears after the loop.
Let's see how list comprehension works in practice:
# Initial data
x = [1, 2, 3, 4, 5, 6]
# Conditional expression inside a list comprehension
parity = ["odd" if i % 2 else "even" for i in x]
print(parity)
# Output: ['odd', 'even', 'odd', 'even', 'odd', 'even']
# Another example with condition
numbers = [1, 2, 3, 4, 5, 6]
result = [i**2 for i in numbers if i%2 == 0]
print(result)
# Output: [4, 16, 36]Python also supports nested list comprehensions to handle more complex data structures:
# Matrix data
x = [[1, 2], [3, 4], [5, 6]]
# Nested list comprehension
y = [col for row in x for col in row]
print(y)
# Output: [1, 2, 3, 4, 5, 6]
# Compare with standard syntax
y_standard = []
for row in x:
for col in row:
y_standard.append(col)
print(y_standard)
# Same output: [1, 2, 3, 4, 5, 6]List comprehensions can express a simple transformation or filter compactly. They are often efficient, but clarity matters more than saving lines: use an ordinary loop when the expression becomes difficult to read. Their notation resembles mathematical set-builder notation, although a Python list preserves order and duplicate values while a mathematical set does not.
For example, [i**2 for i in x] can be read as "square of i for each i in x", which is very similar to mathematical notation .
A lambda expression creates a function object without a def statement. It is most useful for a small function passed directly as an argument.
The body contains exactly one expression, and that expression becomes the return value. It may call a function such as print(), but it cannot contain statement forms such as return, a regular assignment, for, or while. A lambda can be assigned to a variable, but a named def is usually clearer when the function will be reused.
# Basic lambda syntax
lambda parameters : expression
# Simple lambda example
square = lambda x: x**2
print(square(5)) # Output: 25
# Lambda with multiple parameters
add = lambda x, y: x + y
print(add(3, 4)) # Output: 7
# Compare with regular function
def square_normal(x):
return x**2
def add_normal(x, y):
return x + yShort lambdas work well as callbacks, especially a key function passed to sorted(). map() and filter() also accept them, although an equivalent comprehension may be easier to read:
# With map()
numbers = [1, 2, 3, 4, 5]
squared = list(map(lambda x: x**2, numbers))
print(squared) # Output: [1, 4, 9, 16, 25]
# With filter()
even_numbers = list(filter(lambda x: x%2 == 0, numbers))
print(even_numbers) # Output: [2, 4]
# With sorted()
students = [('Alice', 85), ('Bob', 90), ('Charlie', 78)]
sorted_by_grade = sorted(students, key=lambda student: student[1])
print(sorted_by_grade) # Output: [('Charlie', 78), ('Alice', 85), ('Bob', 90)]Python has other compact syntax for common operations. These forms can improve readability, but they do not guarantee better runtime performance.
Python provides more concise assignment operators for common operations:
# Compound assignment
a = 10
a += 1 # same as: a = a + 1
print(a) # Output: 11
a -= 2 # same as: a = a - 2
print(a) # Output: 9
a *= 3 # same as: a = a * 3
print(a) # Output: 27
a /= 3 # same as: a = a / 3
print(a) # Output: 9.0For immutable numbers, these examples produce the same values as their expanded forms. For mutable or user-defined objects, += can perform an in-place operation, so it is not always behaviorally identical to rebinding with a = a + value.
Python allows the use of negative indices to access elements from the back:
# Negative indexing
data = [10, 20, 30, 40, 50]
# Access last element
print(data[-1]) # Output: 50
# same as: data[len(data) - 1]
print(data[-2]) # Output: 40
print(data[-3]) # Output: 30
# Slicing with negative index
print(data[-3:]) # Output: [30, 40, 50]
print(data[:-2]) # Output: [10, 20, 30]Python allows assignment of multiple variables in a single line:
# Multiple assignment
x, y, z = 1, 2, 3
print(f"x={x}, y={y}, z={z}") # Output: x=1, y=2, z=3
# Unpacking list
coordinates = [10, 20]
x, y = coordinates
print(f"x={x}, y={y}") # Output: x=10, y=20
# Swapping variables
a, b = 5, 10
print(f"Before: a={a}, b={b}")
a, b = b, a # Swap without temporary variable
print(f"After: a={a}, b={b}") # Output: After: a=10, b=5To understand the advantages of syntactic sugar, let's compare different ways of writing:
| Concept | Standard Syntax | Syntactic Sugar |
|---|---|---|
| Create squared list | result = [] then loop with append() | result = [i**2 for i in range(5)] |
| Simple function | def double(x): return x * 2 | double = lambda x: x * 2 |
| Assignment | a = a + 5 | a += 5 |
| Access last element | data[len(data) - 1] | data[-1] |
Choose the compact form when it makes the operation easier to recognize. If it hides control flow or side effects, the explicit form is the better explanation and often the better program.