2.15. อาร์กิวเมนต์¶
ฟังก์ชันสามารถเรียกได้หลายวิธี และพารามิเตอร์สามารถประกาศได้หลายรูปแบบ การผสมผสานดูน่ากังวลในตอนแรก แต่สามหรือสี่รูปแบบครอบคลุมเกือบทุกกรณีในทางปฏิบัติ
2.15.1. อาร์กิวเมนต์เชิงตำแหน่งและแบบคีย์เวิร์ด¶
การเรียกที่ง่ายที่สุดส่งอาร์กิวเมนต์ตาม ตำแหน่ง -- ค่าแรกไปยังพารามิเตอร์แรก ค่าที่สองไปยังพารามิเตอร์ที่สอง และต่อไปเรื่อยๆ:
def rect(x, y, w, h):
return (x, y, w, h)
rect(10, 20, 100, 50)
การเรียกเดียวกันสามารถส่งอาร์กิวเมนต์ตาม คีย์เวิร์ด โดยระบุชื่อพารามิเตอร์แต่ละตัวอย่างชัดเจน:
rect(x=10, y=20, w=100, h=50)
อาร์กิวเมนต์แบบคีย์เวิร์ดไม่ขึ้นกับลำดับและทำให้การเรียกอธิบายตัวเองได้ แต่ต้องพิมพ์มากขึ้น อาร์กิวเมนต์เชิงตำแหน่งและแบบคีย์เวิร์ดสามารถผสมกันในการเรียกเดียว แต่ทุกตัวที่เป็นเชิงตำแหน่งต้องอยู่ก่อนตัวที่เป็นคีย์เวิร์ด:
rect(10, 20, w=100, h=50) # OK
rect(x=10, 20, 100, 50) # SyntaxError
2.15.2. ค่าเริ่มต้น¶
พารามิเตอร์สามารถกำหนดค่าเริ่มต้นเพื่อใช้เมื่อผู้เรียกไม่ส่งค่ามา:
def greet(name, greeting="hello"):
print(greeting, name)
greet("Alice") # hello Alice
greet("Alice", "hi") # hi Alice
greet("Alice", greeting="hey") # hey Alice
พารามิเตอร์ที่มีค่าเริ่มต้นต้องอยู่ หลัง พารามิเตอร์ที่ไม่มีค่าเริ่มต้นในบรรทัด def
Warning
ค่าเริ่มต้นจะถูกประเมินครั้งเดียวเมื่อ def รัน ไม่ใช่ทุกครั้งที่เรียก การใช้ค่าเริ่มต้นที่เปลี่ยนแปลงได้ ([], {}) ทำให้ อ็อบเจกต์เดียวกัน ถูกใช้ร่วมกันในทุกการเรียกที่ใช้ค่าเริ่มต้น ใช้ None เป็น sentinel แทน:
def append_to(item, target=None):
if target is None:
target = []
target.append(item)
return target
2.15.3. ความยาวแปรผัน: *args และ **kwargs¶
พารามิเตอร์ที่นำหน้าด้วย * จะรวบรวมอาร์กิวเมนต์เชิงตำแหน่งที่เหลือทั้งหมดเป็น tuple พารามิเตอร์ที่นำหน้าด้วย ** จะรวบรวมอาร์กิวเมนต์แบบคีย์เวิร์ดที่เหลือทั้งหมดเป็น dict ชื่อตามธรรมเนียมคือ args และ kwargs แต่จะใช้ตัวระบุอื่นก็ได้:
def report(label, *values, **options):
print(label, values, options)
report("temps", 21, 22, 23, unit="C", precision=1)
ผลลัพธ์:
temps (21, 22, 23) {'unit': 'C', 'precision': 1}
ฟังก์ชันส่วนใหญ่ไม่จำเป็นต้องใช้ทั้งสอง การใช้งานที่พบบ่อยที่สุดคือการส่งต่ออาร์กิวเมนต์จาก wrapper ไปยังการเรียกภายใน:
def log_and_call(func, *args, **kwargs):
print("calling", func.__name__)
return func(*args, **kwargs)
ไวยากรณ์กระจก ณ ตำแหน่งเรียก จะแกะ iterable เป็นอาร์กิวเมนต์เชิงตำแหน่ง (*) หรือ dict เป็นอาร์กิวเมนต์แบบคีย์เวิร์ด (**):
point = (10, 20, 100, 50)
rect(*point) # same as rect(10, 20, 100, 50)
kwargs = {"x": 10, "y": 20, "w": 100, "h": 50}
rect(**kwargs) # same as rect(x=10, y=20, ...)
2.15.4. พารามิเตอร์แบบ keyword-only¶
* ที่อยู่ลำพังในรายการพารามิเตอร์ (ไม่ติดกับชื่อ) จะทำเครื่องหมายทุกพารามิเตอร์ที่ตามมาว่าเป็น keyword-only -- ผู้เรียกต้องใช้ชื่อ:
def crop(buffer, *, x, y, w, h):
...
crop(buffer, x=0, y=0, w=100, h=100) # OK
crop(buffer, 0, 0, 100, 100) # TypeError
ใช้สิ่งนี้สำหรับ flag บูลีนและอาร์กิวเมนต์อื่นๆ ที่ค่าเปล่าๆ ณ ตำแหน่งเรียกจะไม่อธิบายตัวเองได้