رفتن به محتوا
پایتون از صفراصول زباندرس ۵ از ۱۰

تابع

کد را به تکه‌های اسم‌دار و قابل‌استفاده‌ی دوباره تقسیم کن: def، پارامتر و آرگومان، return و فرقش با print، مقدار پیش‌فرض و آرگومان با اسم، برگرداندن چند مقدار، docstring، دامنه‌ی متغیرها، lambda برای sorted، و تله‌ی لیست به‌عنوان مقدار پیش‌فرض.

  • حدود ۲۰ دقیقه مطالعه
  • ۱۰ مثال اجراشده
  • ۳ تمرین با جواب
  • مقدماتی تا متوسط
  • به‌روزرسانی: ۲۹ مهر ۱۴۰۵

توی این درس یاد می‌گیری تکه‌ای از کد را یک بار با def بنویسی، به آن اسم بدهی و هر بار لازم شد صدایش بزنی. ورودی تابع را با پارامتر می‌دهی و نتیجه را با return پس می‌گیری (و می‌فهمی چرا return با print فرق دارد). مقدار پیش‌فرض و آرگومان با اسم را یاد می‌گیری، چند مقدار را با هم برمی‌گردانی، با docstring تابعت را توضیح می‌دهی، و می‌بینی متغیرهای داخل تابع چرا بیرونش دیده نمی‌شوند. lambda را هم برای مرتب‌سازی می‌شناسی.

فرض کن در سه جای برنامه باید قیمت یک سبد خرید را حساب کنی. سه بار همان پنج خط را کپی می‌کنی. فردا قیمت‌ها مالیات می‌گیرند و باید فرمول عوض شود: حالا سه جا را باید درست کنی، و احتمالاً یکی را فراموش می‌کنی. تابع این مشکل را حل می‌کند: یک بار بنویس، هر جا لازم شد صدا بزن، و اگر عوض شد، فقط یک جا را عوض کن.

تشبیه: دستگاه آبمیوه‌گیری

Section titled “تشبیه: دستگاه آبمیوه‌گیری”

تابع مثل دستگاه آبمیوه‌گیری است: از یک طرف ورودی (پرتقال) می‌دهی، دستگاه کارش را می‌کند و از طرف دیگر خروجی (آب پرتقال) می‌دهد. لازم نیست هر بار بدانی داخلش چه می‌گذرد؛ فقط باید بدانی چه بدهی و چه پس بگیری. پارامتر دهانه‌ی ورودی است و return شیر خروجی.

آرگومان‌ها به پارامترها داده می‌شوند، بدنه‌ی تابع اجرا می‌شود و مقدار return به جایی که تابع صدا زده شده برمی‌گردد.
greet.py
def greet(name):
print(f"سلام {name}!")
greet("علی")
greet("سارا")
خروجی
سلام علی!
سلام سارا!
  • def (مخفف define) یک تابع تعریف می‌کند: اسم، پرانتز با پارامترها، و دونقطه.
  • بدنهی تابع، مثل if، تورفته است.
  • تعریف کردن تابع اجرایش نمی‌کند. خط‌های greet("علی") آن را صدا می‌زنند (call) و هر بار بدنه با یک مقدار متفاوت برای name اجرا می‌شود.
  • name در تعریف یک پارامتر است و "علی" در صدا زدن یک آرگومان.

مثال ۲: برگرداندن نتیجه، return

Section titled “مثال ۲: برگرداندن نتیجه، return”
area.py
def area(width, height):
return width * height
a = area(3, 4)
print(a)
print(area(10, 2) + area(1, 1))
خروجی
12
21

return مقدار را به جایی که تابع صدا زده شده برمی‌گرداند؛ انگار area(3, 4) با 12 جایگزین شده. برای همین می‌شود نتیجه را در متغیر گذاشت یا در یک حساب دیگر به کار برد. وقتی return اجرا شود، تابع همان‌جا تمام می‌شود.

اشتباه شماره‌ی یک تازه‌کارها:

add.py
def add(a, b):
print(a + b)
x = add(2, 3)
print("مقدار x:", x)
خروجی
5
مقدار x: None

print نتیجه را روی صفحه نشان داد، ولی چیزی برنگرداند. تابعی که return ندارد خودکار مقدار ویژه‌ی None (یعنی «هیچ») را برمی‌گرداند، پس x خالی ماند. قاعده: تابعی که چیزی حساب می‌کند، return کند؛ چاپ کردن را به کسی بسپار که صدایش زده.

print برای آدم است و روی صفحه می‌نویسد؛ return برای برنامه است و مقدار را برمی‌گرداند تا بشود با آن کار کرد.

مثال ۴: مقدار پیش‌فرض و آرگومان با اسم

Section titled “مثال ۴: مقدار پیش‌فرض و آرگومان با اسم”
backup.py
def backup_name(filename, ext="bak", stamp=False):
name = f"{filename}.{ext}"
if stamp:
name = "2026-10-21_" + name
return name
print(backup_name("app.conf"))
print(backup_name("app.conf", "old"))
print(backup_name("app.conf", stamp=True))
print(backup_name(stamp=True, filename="db.sql", ext="gz"))
خروجی
app.conf.bak
app.conf.old
2026-10-21_app.conf.bak
2026-10-21_db.sql.gz
  • ext="bak" یعنی «اگر کسی مقدار نداد، bak باشد». پارامترهای پیش‌فرض‌دار اختیاریاند.
  • آرگومان‌ها را می‌شود به ترتیب داد ("app.conf", "old") یا با اسم (stamp=True). با اسم، ترتیب مهم نیست و خواندن کد خیلی راحت‌تر است: stamp=True خودش می‌گوید یعنی چه، ولی یک True تنها نه.
  • پارامترهای بدون پیش‌فرض باید قبل از پیش‌فرض‌دارها بیایند.

مثال ۵: چند مقدار برگرداندن و docstring

Section titled “مثال ۵: چند مقدار برگرداندن و docstring”
stats.py
def stats(nums):
"""میانگین، کمترین و بیشترین یک لیست عددی را برمی‌گرداند."""
return sum(nums) / len(nums), min(nums), max(nums)
avg, low, high = stats([4, 8, 15, 16, 23, 42])
print(avg, low, high)
help(stats)
خروجی
18.0 4 42
Help on function stats in module __main__:
stats(nums)
میانگین، کمترین و بیشترین یک لیست عددی را برمی‌گرداند.
  • return a, b, c در واقع یک tuple سه‌تایی برمی‌گرداند، و avg, low, high = ... آن را باز می‌کند و هر عضو را در یک متغیر می‌گذارد.
  • رشته‌ای که در خط اول بدنه با سه کوتیشن ("""...""") می‌آید docstring است: توضیح تابع، که help() و ویرایشگرها نشانش می‌دهند. برای هر تابعی که دیگران (یا خودت ماه بعد) استفاده می‌کنند، یک docstring کوتاه بنویس.
⚡ بررسی سریع

def f(): return 1, 2 ؛ بعد از a, b = f() مقدار b چیست؟

مثال ۶: تابع روی داده‌ی واقعی

Section titled “مثال ۶: تابع روی داده‌ی واقعی”
cart.py
def total_price(items):
total = 0
for item in items:
total += item["price"] * item["qty"]
return total
cart = [
{"name": "کتاب", "price": 120000, "qty": 2},
{"name": "خودکار", "price": 15000, "qty": 5},
]
print(f"جمع سبد: {total_price(cart):,} تومان")
خروجی
جمع سبد: 315,000 تومان

تابع لیستی از دیکشنری‌ها (درس قبل) می‌گیرد و یک عدد برمی‌گرداند. حالا هر جای برنامه که جمع سبد لازم است، فقط total_price(cart) می‌نویسی؛ و اگر روزی مالیات اضافه شد، فقط داخل همین تابع را عوض می‌کنی.

مثال ۷: تابع‌هایی که تابع صدا می‌زنند

Section titled “مثال ۷: تابع‌هایی که تابع صدا می‌زنند”
even.py
def is_even(n):
return n % 2 == 0
def first_even(nums):
for n in nums:
if is_even(n):
return n
return None
print(first_even([3, 7, 10, 12]))
print(first_even([1, 3, 5]))
خروجی
10
None

برنامه‌های خوب از تابع‌های کوچک با اسم‌های گویا ساخته می‌شوند: if is_even(n) تقریباً مثل یک جمله‌ی انگلیسی خوانده می‌شود. return n داخل حلقه هم حلقه و هم تابع را با هم تمام می‌کند؛ برای همین 12 هیچ‌وقت بررسی نشد. اگر حلقه بدون پیدا کردن تمام شود، return None آخر اجرا می‌شود.

مثال ۸: دامنه‌ی متغیرها

Section titled “مثال ۸: دامنه‌ی متغیرها”
scope.py
count = 10
def show():
count = 99
print("داخل تابع:", count)
show()
print("بیرون تابع:", count)
خروجی
داخل تابع: 99
بیرون تابع: 10

متغیری که داخل تابع ساخته می‌شود محلی (local) است: فقط داخل همان تابع وجود دارد و با تمام شدن تابع از بین می‌رود. count = 99 یک متغیر جدید داخل تابع ساخت و به count بیرونی دست نزد. این ویژگی خوبی است: تابع‌ها نمی‌توانند تصادفاً متغیرهای بقیه‌ی برنامه را خراب کنند. قاعده: داده را با پارامتر به تابع بده و با return پس بگیر؛ به متغیرهای بیرونی تکیه نکن.

مثال ۹: lambda، تابع یک‌خطی برای sorted

Section titled “مثال ۹: lambda، تابع یک‌خطی برای sorted”

گاهی فقط یک تابع کوچک و یک‌بارمصرف لازم است؛ مثلاً برای گفتن به sorted که «بر اساس چه چیزی مرتب کن»:

sort_servers.py
servers = [{"name": "web1", "disk": 72}, {"name": "db1", "disk": 91}, {"name": "web2", "disk": 95}]
by_disk = sorted(servers, key=lambda s: s["disk"], reverse=True)
print([s["name"] for s in by_disk])
خروجی
['web2', 'db1', 'web1']

lambda s: s["disk"] یعنی «تابعی که s می‌گیرد و s["disk"] را برمی‌گرداند»؛ همان def get_disk(s): return s["disk"] در یک خط. sorted آن را روی هر عضو صدا می‌زند و بر اساس نتیجه مرتب می‌کند. برای هر چیزی بزرگ‌تر از یک عبارت، همان def معمولی بهتر است.

مثال ۱۰: راهنمای نوع (type hint)

Section titled “مثال ۱۰: راهنمای نوع (type hint)”

می‌توانی بنویسی هر پارامتر و خروجی چه نوعی باید باشد:

temp.py
def celsius_to_f(c: float) -> float:
return c * 9 / 5 + 32
for c in [0, 25, 37, 100]:
print(f"{c}°C = {celsius_to_f(c):.1f}°F")
خروجی
0°C = 32.0°F
25°C = 77.0°F
37°C = 98.6°F
100°C = 212.0°F

c: float و -> float را پایتون اجبار نمی‌کند؛ فقط توضیح‌اند. ولی ویرایشگرها و ابزارهای بررسی کد از آن‌ها استفاده می‌کنند تا اشتباه‌ها را قبل از اجرا نشانت بدهند. در کدهای جدید زیاد می‌بینی‌شان.

پشت پرده: صدا زدن تابع چه می‌کند؟

Section titled “پشت پرده: صدا زدن تابع چه می‌کند؟”

وقتی area(3, 4) را صدا می‌زنی، پایتون یک قاب (frame) تازه در حافظه می‌سازد: یک فضای خصوصی برای متغیرهای همین اجرا (width=3، height=4). بدنه در همین قاب اجرا می‌شود؛ با return، مقدار به قاب صدازننده برمی‌گردد و قاب تابع پاک می‌شود. برای همین متغیرهای محلی بیرون دیده نمی‌شوند، و برای همین هر صدا زدن مستقل از قبلی است. آن Traceback که در پیام خطاها می‌بینی، دقیقاً فهرست همین قاب‌هاست: «از خط ۱۰ تابع main صدا زده شد، که از خط ۴ تابع load را صدا زد، که آنجا خطا رخ داد».

یک نکته‌ی ظریف: مقدارها با اشاره به تابع داده می‌شوند (مثل b = a در درس قبل). پس اگر لیستی به تابع بدهی و تابع append کند، لیست بیرونی هم عوض می‌شود. همین منشأ تله‌ی اشتباه رایج ۵ است.

شکل معنی
def f(a, b): تعریف تابع با دو پارامتر
return x برگرداندن x و تمام کردن تابع
def f(a, b=10): b اختیاری با پیش‌فرض ۱۰
f(1, b=5) آرگومان با اسم
return a, b و x, y = f() چند مقدار
"""توضیح""" docstring (خط اول بدنه)
lambda x: x * 2 تابع یک‌خطی بی‌اسم
def f(x: int) -> str: راهنمای نوع
خطا معنی
NameError: name 'f' is not defined تابع قبل از تعریفش صدا زده شده (یا غلط تایپی)
TypeError: f() missing 1 required positional argument آرگومان کم داده‌ای
TypeError: f() takes 2 positional arguments but 3 were given آرگومان زیاد داده‌ای

۱) صدا زدن تابع قبل از تعریفش

Section titled “۱) صدا زدن تابع قبل از تعریفش”
print(square(4))
def square(n):
return n * n
خروجی
Traceback (most recent call last):
File "/home/ali/py/order.py", line 1, in <module>
print(square(4))
^^^^^^
NameError: name 'square' is not defined

پایتون از بالا به پایین اجرا می‌کند و در خط ۱ هنوز def را ندیده. راه‌حل: تعریف‌ها را بالای فایل بگذار.

def area(width, height):
return width * height
print(area(3))
خروجی
Traceback (most recent call last):
File "/home/ali/py/args.py", line 4, in <module>
print(area(3))
^^^^^^^
TypeError: area() missing 1 required positional argument: 'height'

پیام دقیقاً می‌گوید کدام پارامتر جا افتاده. راه‌حل: همه‌ی پارامترهای بدون پیش‌فرض را بده.

مثال ۳: نتیجه None می‌شود. راه‌حل: تابعی که چیزی حساب می‌کند، return کند.

۴) فراموش کردن پرانتز هنگام صدا زدن

Section titled “۴) فراموش کردن پرانتز هنگام صدا زدن”

greet (بدون پرانتز) تابع را صدا نمی‌زند؛ فقط به خود تابع اشاره می‌کند. print(greet) چیزی مثل <function greet at 0x7f...> چاپ می‌کند. راه‌حل: greet("علی").

۵) لیست به‌عنوان مقدار پیش‌فرض

Section titled “۵) لیست به‌عنوان مقدار پیش‌فرض”
def add_item(item, basket=[]):
basket.append(item)
return basket
print(add_item("سیب"))
print(add_item("موز"))
خروجی
['سیب']
['سیب', 'موز']

انتظار داشتی دومی فقط ['موز'] باشد! مقدار پیش‌فرض یک بار، هنگام تعریف تابع، ساخته می‌شود؛ پس همه‌ی صدا زدن‌ها همان یک لیست را می‌بینند. راه‌حل: پیش‌فرض را None بگذار و داخل تابع لیست تازه بساز:

def add_item(item, basket=None):
if basket is None:
basket = []
basket.append(item)
return basket
print(add_item("سیب"))
print(add_item("موز"))
خروجی
['سیب']
['موز']
تمرینآسان

تابع circle_area(r) بنویس که مساحت دایره (3.14159 × r × r) را برگرداند. با سه شعاع مختلف صدایش بزن و نتیجه را با دو رقم اعشار چاپ کن.

دیدن جواب
circle.py
def circle_area(r):
return 3.14159 * r * r
for r in [1, 2.5, 10]:
print(f"شعاع {r}: {circle_area(r):.2f}")
خروجی
شعاع 1: 3.14
شعاع 2.5: 19.63
شعاع 10: 314.16

(در درس ماژول‌ها می‌بینی math.pi عدد دقیق‌تر پی را دارد.)

تمرینمتوسط

تمرین اصلی: تابع password_strength(pw) بنویس که یک رمز بگیرد و یکی از سه متن "ضعیف"، "متوسط" یا "قوی" را برگرداند: قوی اگر دست‌کم ۱۲ حرف باشد و دست‌کم یک رقم داشته باشد؛ متوسط اگر دست‌کم ۸ حرف باشد؛ وگرنه ضعیف. با چند رمز امتحانش کن. (راهنما: any(ch.isdigit() for ch in pw) می‌گوید آیا دست‌کم یک رقم هست.)

دیدن جواب
strength.py
def password_strength(pw):
"""قدرت رمز را با سه سطح برمی‌گرداند."""
has_digit = any(ch.isdigit() for ch in pw)
if len(pw) >= 12 and has_digit:
return "قوی"
elif len(pw) >= 8:
return "متوسط"
else:
return "ضعیف"
for pw in ["1234", "sunshine", "correcthorse", "correcthorse9"]:
print(pw, "→", password_strength(pw))
خروجی
1234 → ضعیف
sunshine → متوسط
correcthorse → متوسط
correcthorse9 → قوی

correcthorse دوازده حرف دارد ولی رقم ندارد، پس شرط and غلط شد و به elif رسید.

تمرینسخت

تابع top_n(counts, n=3) بنویس که یک دیکشنری شمارش (مثل {"200": 50, "404": 7, ...}) بگیرد و n کلید پرتکرار را به شکل لیستی از tupleها برگرداند. پیش‌فرض ۳ باشد. یک بار بدون n و یک بار با n=1 صدایش بزن.

دیدن جواب
top.py
def top_n(counts, n=3):
"""n کلید پرتکرار را به ترتیب نزولی برمی‌گرداند."""
ordered = sorted(counts.items(), key=lambda kv: kv[1], reverse=True)
return ordered[:n]
codes = {"200": 50, "404": 7, "500": 2, "301": 12, "403": 1}
print(top_n(codes))
print(top_n(codes, n=1))
خروجی
[('200', 50), ('301', 12), ('404', 7)]
[('200', 50)]

ordered[:n] یعنی «n عضو اول» (برش از ابتدا). چون n پیش‌فرض دارد، صدا زدن بدون آن هم کار می‌کند.

آزمونک
  1. تعریف یک تابع با def...

  2. تابعی که return ندارد چه برمی‌گرداند؟

  3. در def f(a, b=2): کدام صدا زدن خطا می‌دهد؟

  4. متغیری که داخل تابع ساخته شده…

  5. sorted(items, key=lambda x: x[1]) بر اساس چه چیزی مرتب می‌کند؟

  6. چرا def f(x, items=[]) خطرناک است؟

  • def اسم(پارامترها): + بدنه‌ی تورفته؛ با اسم(آرگومان‌ها) صدا زده می‌شود.
  • return مقدار را برمی‌گرداند و تابع را تمام می‌کند؛ بدون آن، تابع None برمی‌گرداند. print فقط نمایش است.
  • مقدار پیش‌فرض (b=10) پارامتر را اختیاری می‌کند؛ آرگومان با اسم (stamp=True) کد را خوانا.
  • return a, b و x, y = f() برای چند مقدار؛ docstring برای توضیح.
  • متغیرهای داخل تابع محلی‌اند؛ داده را با پارامتر بده و با return بگیر.
  • lambda برای تابع‌های یک‌خطی (مثل key در sorted)؛ هرگز لیست را پیش‌فرض نگذار.
برگه‌ی تقلب این درس
دستورکاری که می‌کند
def f(a, b=1):تعریف با پیش‌فرض
return a + bبرگرداندن نتیجه
x = f(2, b=3)صدا زدن با آرگومان با اسم
return a, b / x, y = f()چند مقدار
"""توضیح تابع"""docstring
help(f)دیدن docstring
lambda s: s["disk"]تابع یک‌خطی
sorted(x, key=..., reverse=True)مرتب‌سازی با کلید
def f(x=None): if x is None: x = []جایگزین امن برای پیش‌فرض لیست