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 บูลีนและอาร์กิวเมนต์อื่นๆ ที่ค่าเปล่าๆ ณ ตำแหน่งเรียกจะไม่อธิบายตัวเองได้