Skip to content

Unpacking, *args & **kwargs

TypeScript’s ... spread operator handles both arrays and objects. Python splits the concept into two operators: * for sequences (lists, tuples, iterables) and ** for dictionaries. The * operator maps closely to what you already know from TypeScript destructuring and spread. The ** operator for dicts has no direct TypeScript equivalent — it is Python-specific, and it is also the syntax for variadic keyword arguments in function signatures.

Python lets you unpack any iterable into variables in a single assignment. This is more powerful than TypeScript destructuring because it works on any iterable, not just arrays and objects.

TypeScript
// TypeScript: array destructuring
const [x, y, z] = [1, 2, 3];
console.log(x, y, z); // 1 2 3
// Rest element
const [first, ...rest] = [10, 20, 30, 40, 50];
console.log(first, rest); // 10 [20, 30, 40, 50]
// Swap with destructuring
let a = 5, b = 10;
[a, b] = [b, a];
console.log(a, b); // 10 5
Python
# Python: tuple unpacking
x, y, z = 1, 2, 3
print(x, y, z) # 1 2 3
# Starred assignment (captures middle or end)
first, *middle, last = [10, 20, 30, 40, 50]
print(first, middle, last) # 10 [20, 30, 40] 50
# Swap without a temp variable
a, b = 5, 10
a, b = b, a
print(a, b) # 10 5

Python’s starred assignment (*middle) is more flexible than TypeScript’s rest element — you can place it anywhere (first, middle, or last position), and Python figures out what goes where.

*args in a function signature collects any number of positional arguments into a tuple. The name args is a convention — the * is what matters.

TypeScript
// TypeScript: rest parameters
function sumAll(...args: number[]): number {
return args.reduce((acc, n) => acc + n, 0);
}
console.log(sumAll(1, 2, 3, 4, 5)); // 15
// Spreading an array into a function call
const nums = [1, 2, 3];
console.log(Math.max(...nums)); // 3
Python
# Python: *args collects positional arguments into a tuple
def sum_all(*args):
return sum(args)
print(sum_all(1, 2, 3, 4, 5)) # 15
# Spreading a list into a function call with *
nums = [1, 2, 3]
print(max(*nums)) # 3

TypeScript has no built-in equivalent to **kwargs. The closest pattern is accepting an options object and destructuring it. In Python, **kwargs collects any keyword arguments not matched by named parameters into a dict.

TypeScript
// TypeScript: simulate kwargs with an options object
function greet(options: Record<string, string | number>): void {
for (const [key, val] of Object.entries(options)) {
console.log(`${key}: ${val}`);
}
}
greet({ name: "Alice", age: 30, city: "Bangkok" });
// Object spread / merge
const defaults = { color: "blue", size: "medium" };
const overrides = { color: "red", weight: "heavy" };
const merged = { ...defaults, ...overrides };
console.log(merged);
Python
# Python: **kwargs collects keyword arguments into a dict
def greet(**kwargs):
for key, val in kwargs.items():
print(f"{key}: {val}")
greet(name="Alice", age=30, city="Bangkok")
# Dict merge with **
defaults = {"color": "blue", "size": "medium"}
overrides = {"color": "red", "weight": "heavy"}
merged = {**defaults, **overrides}
print(merged)
# Tuple unpacking
x, y, z = 1, 2, 3
print(x, y, z)
# Starred assignment
first, *middle, last = [10, 20, 30, 40, 50]
print(first, middle, last)
# Swap without temp variable
a, b = 5, 10
a, b = b, a
print(a, b)
def sum_all(*args):
return sum(args)
print(sum_all(1, 2, 3, 4, 5))
def greet(**kwargs):
for key, val in kwargs.items():
print(f"{key}: {val}")
greet(name="Alice", age=30, city="Bangkok")
defaults = {"color": "blue", "size": "medium"}
overrides = {"color": "red", "weight": "heavy"}
merged = {**defaults, **overrides}
print(merged)
Given first, *middle, last = [1, 2, 3, 4, 5], what is middle?
What type does *args collect its arguments into inside the function?
In the parameter list def f(a, *args, b, **kwargs), what kind of parameter is b?
What does {**dict1, **dict2} produce when dict1 and dict2 share a key?