توابع

آرگومان‌های تابع در پایتون: موقعیتی، کلیدی (keyword) و مقدار پیش‌فرض

۳ دقیقه مطالعه · به‌روزرسانی ۲۲ مهر ۱۴۰۵

وقتی تابعی چند پارامتر دارد، پایتون از کجا می‌فهمد کدام مقدار مال کدام پارامتر است؟ دو راه دارد: ترتیب و اسم.

آرگومان موقعیتی (Positional)

ساده‌ترین حالت: مقدارها به همان ترتیب پارامترها داده می‌شوند.

def greet(name, age, title):
    print(f"Hello dear {title} {name}, you are {age} years old.")

greet("Sara", 30, "Dr.")

اولی به name، دومی به age، سومی به title. اگر ترتیب را اشتباه بدهید، پایتون نمی‌فهمد:

def greet(name, age, title):
    print(f"Hello dear {title} {name}, you are {age} years old.")

greet("Dr.", "Sara", 30)

خطایی نمی‌گیرید، ولی خروجی بی‌معنی است. یک خطای منطقی کلاسیک!

آرگومان کلیدی (Keyword)

می‌توانید هنگام صدا زدن، اسم پارامتر را هم بنویسید. آن وقت ترتیب مهم نیست:

def greet(name, age, title):
    print(f"Hello dear {title} {name}, you are {age} years old.")

greet(title="Madam", age=60, name="Zahra")
greet("Zahra", title="Madam", age=60)   # ترکیب هر دو

مزیت دیگرش خوانایی است. مقایسه کنید:

print_name("Eric", "Grimson", False)          # False یعنی چه؟
print_name("Eric", "Grimson", reverse=False)  # آهان!

قانون ترتیب

وقتی ترکیب می‌کنید، اول موقعیتی‌ها، بعد کلیدی‌ها:

def greet(name, age, title):
    print(f"Hello dear {title} {name}, you are {age} years old.")

greet(name="Zahra", 60, "Madam")

اجرا کنید: SyntaxError: positional argument follows keyword argument. وقتی یک آرگومان را با اسم دادید، بعد از آن دیگر نمی‌شود فقط با ترتیب مقدار داد.

مقدار پیش‌فرض (Default)

می‌توانید برای بعضی پارامترها مقدار پیش‌فرض بگذارید. اگر صداکننده مقداری نداد، همان استفاده می‌شود:

def greet(name, age=20, title="sir"):
    print(f"Hello dear {title} {name}, you are {age} years old.")

greet("Ali")
greet("Ali", 33)
greet("Ali", age=90)
greet("Ali", title="Dr.")    # age پیش‌فرض می‌ماند، فقط title عوض می‌شود

مثال کلاسیک: یک پرچم اختیاری

def print_name(first_name, last_name, reverse=False):
    if reverse:
        print(last_name + ", " + first_name)
    else:
        print(first_name, last_name)

print_name("Eric", "Grimson")
print_name("Eric", "Grimson", True)
print_name("Eric", "Grimson", reverse=True)
print_name(last_name="Grimson", first_name="Eric")

همهٔ این صدا زدن‌ها مجازند.

💡 خیلی از توابع داخلی پایتون همین‌طور ساخته شده‌اند. print را یادتان هست؟ sep=" " و end="\n" پارامترهای پیش‌فرض آن هستند. برای همین معمولاً نمی‌بینیدشان، ولی هر وقت لازم بود عوضشان می‌کنید.

⚠️ پارامترهای با مقدار پیش‌فرض باید بعد از پارامترهای بدون پیش‌فرض بیایند. def f(a=1, b): خطای نحوی است.

خروجی یک تابع، ورودی تابع دیگر

آرگومان می‌تواند هر عبارتی باشد، از جمله صدا زدن یک تابع دیگر. پایتون از داخلی‌ترین پرانتز شروع می‌کند:

def bigger(a, b):
    if a > b:
        return a
    else:
        return b

print(bigger(bigger(5, 11), 3))

قدم به قدم:

print(bigger(bigger(5, 11), 3))
             └─────┬─────┘
                   11
print(bigger(      11    , 3))
      └─────────┬─────────┘
                11
print(          11          )
  1. اول bigger(5, 11) اجرا می‌شود و 11 برمی‌گرداند.
  2. حالا عبارت می‌شود bigger(11, 3) که 11 برمی‌گرداند.
  3. در آخر print(11).

این فقط وقتی کار می‌کند که تابع درونی return کند. اگر bigger به‌جای return از print استفاده می‌کرد، تابع بیرونی None می‌گرفت. (چرا؟)

💡 در پایتون خود توابع هم «شیء» هستند و می‌شود خود تابع (نه نتیجه‌اش) را به تابع دیگری داد: sorted(names, key=len). این ایدهٔ قدرتمندی است که بعداً با lambda و توابع مرتبهٔ بالاتر به آن برمی‌گردیم.

تمرین

تابع power(base, exp=2) بنویسید که base به توان exp را برگرداند و پیش‌فرضش مربع باشد. بعد با یک خط و بدون متغیر کمکی، (3²)³ را حساب کنید.

جواب
def power(base, exp=2):
    return base ** exp

print(power(5))              # 25
print(power(2, 10))          # 1024
print(power(power(3), 3))    # (3²)³ = 729
print(power(exp=3, base=2))  # 8