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

Args, Kwargs และ Parameter

Python แยกความแตกต่างระหว่าง parameter (ชื่อที่อยู่ในนิยามของ function) กับ argument (ค่าที่ส่งเข้าไปตอนเรียกใช้) Python ให้เราควบคุมได้อย่างละเอียดว่าผู้เรียกจะส่งค่าเหล่านั้นเข้ามาได้อย่างไร

โดยปกติแล้ว ทุก parameter สามารถส่งค่าแบบ positional หรือแบบระบุชื่อ keyword ก็ได้

def connect(host: str, port: int, timeout: int = 30) -> str:
return f"{host}:{port} (timeout={timeout}s)"
# Positional
connect("localhost", 5432)
# Keyword — order does not matter
connect(port=5432, host="localhost")
# Mixed — positional first, then keyword
connect("localhost", port=5432, timeout=60)

timeout มี ค่า default เป็น 30 จึงเป็นค่าที่ใส่หรือไม่ก็ได้ positional argument จะต้องมาก่อน keyword argument เสมอ ณ จุดที่เรียกใช้

ใส่ * นำหน้า parameter เพื่อรวบ positional argument จำนวนเท่าใดก็ได้เข้ามาเป็น tuple

def total(*amounts: float) -> float:
return sum(amounts)
print(total(10.0, 20.5, 5.0)) # 35.5
print(total()) # 0.0

ใส่ ** นำหน้า parameter เพื่อรวบ keyword argument จำนวนเท่าใดก็ได้เข้ามาเป็น dict

def log_event(event: str, **metadata) -> None:
parts = [f"event={event}"]
for key, value in metadata.items():
parts.append(f"{key}={value}")
print(", ".join(parts))
log_event("login", user_id=42, ip="127.0.0.1")
# event=login, user_id=42, ip=127.0.0.1

parameter ใด ๆ ที่อยู่ หลัง * เปล่า ๆ (หรือหลัง *args) จะส่งค่าได้ผ่าน keyword เท่านั้น ส่งแบบ positional ไม่ได้ วิธีนี้ทำให้ API อธิบายตัวเองได้ในตัว และป้องกันความผิดพลาดเรื่องลำดับของ argument

def send_email(to: str, subject: str, *, cc: str = "", bcc: str = "") -> None:
print(f"To: {to} | Subject: {subject} | CC: {cc} | BCC: {bcc}")
send_email("[email protected]", "Hello", cc="[email protected]")
# Calling send_email("[email protected]", "Hi", "[email protected]") would raise TypeError

ลำดับของชนิด parameter ในนิยามจะต้องเป็นแบบนี้เสมอ:

  1. Positional-or-keyword (x, y)
  2. *args (หรือ * เปล่า ๆ)
  3. Keyword-only (key=value หลัง *)
  4. **kwargs
def describe(
name: str,
*adjectives: str,
separator: str = ", ",
**extras
) -> str:
adj_str = separator.join(adjectives) if adjectives else "no adjectives"
extra_str = ", ".join(f"{k}={v}" for k, v in extras.items())
result = f"{name}: {adj_str}"
if extra_str:
result += f" ({extra_str})"
return result
print(describe("Python"))
print(describe("Python", "fast", "readable"))
print(describe("Python", "fast", "readable", separator=" | "))
print(describe("Python", "fast", separator=" + ", version="3.11", typed=True))
*args รวบ argument เข้ามาเป็น type อะไร?
parameter ที่นิยามไว้หลัง `*` เปล่า ๆ ใน signature ของ function คือ:
ทำไม `def f(items=[])` ถึงอันตราย?
ลำดับของชนิด parameter ที่ถูกต้องใน signature ของ function ใน Python คืออะไร?