ข้ามไปยังเนื้อหา

Unpacking, *args และ **kwargs

ฝั่ง TypeScript ใช้ operator ... ตัวเดียวคุมทั้ง array และ object ส่วน Python แยกออกเป็นสองตัว คือ * สำหรับ sequence (list, tuple, iterable) และ ** สำหรับ dictionary

ตัว * ใกล้เคียงกับ destructuring และ spread ที่คุณคุ้นอยู่แล้ว แต่ ** สำหรับ dict ไม่มีตัวเทียบตรง ๆ ใน TypeScript เพราะเป็นของ Python โดยเฉพาะ และยังเป็น syntax สำหรับ variadic keyword argument ใน function signature อีกด้วย

Python ให้คุณ unpack iterable ใดก็ตามลงใน variable ในการ assign ครั้งเดียว สิ่งนี้มีความสามารถมากกว่า destructuring ของ TypeScript เพราะทำงานได้กับ iterable ทุกชนิด ไม่ใช่แค่ array และ object

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

starred assignment ของ Python (*middle) ยืดหยุ่นกว่า rest element ของ TypeScript เพราะวางไว้ตำแหน่งไหนก็ได้ ทั้งต้น กลาง หรือท้าย แล้ว Python จะคำนวณเองว่าค่าไหนควรตกอยู่ที่ใด

*args ใน function signature จะรวบรวม positional argument จำนวนเท่าใดก็ได้เข้าเป็น tuple ชื่อ args เป็นแค่ convention — * คือสิ่งที่สำคัญ

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 ไม่มีตัวเทียบตรง ๆ กับ **kwargs ท่าที่ใกล้ที่สุดคือรับ options object เข้ามาแล้ว destructure ต่อ ส่วน **kwargs ของ Python จะรวบ keyword argument ทุกตัวที่ไม่ตรงกับ parameter ที่ประกาศชื่อไว้ มัดรวมเป็น 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)
จาก first, *middle, last = [1, 2, 3, 4, 5], middle คืออะไร?
*args รวบรวม argument เข้าใน type อะไรภายใน function?
ใน parameter list def f(a, *args, b, **kwargs), b เป็น parameter ชนิดใด?
{**dict1, **dict2} ให้ผลลัพธ์อย่างไรเมื่อ dict1 และ dict2 มี key ร่วมกัน?