توابع
توابع به ما اجازه میدهند کد را سازماندهی، قابل استفاده مجدد و خوانا بسازیم. در این فصل با تعریف تابع، انواع پارامتر، scope و توابع توکار پایتون آشنا میشویم.
توابع به ما اجازه میدهند کد را سازماندهی، قابل استفاده مجدد و خوانا بسازیم. در این فصل با تعریف تابع، انواع پارامتر، scope و توابع توکار پایتون آشنا میشویم.
چرا تابع؟
فرض کنید میخواهید مالیات یک قیمت را چندین بار حساب کنید:
# بدون تابع - تکرار کد
price1 = 100000
tax1 = price1 * 0.09
total1 = price1 + tax1
price2 = 250000
tax2 = price2 * 0.09
total2 = price2 + tax2
# با تابع - بسیار بهتر
def calculate_total(price, tax_rate=0.09):
tax = price * tax_rate
return price + tax
total1 = calculate_total(100000)
total2 = calculate_total(250000)
total3 = calculate_total(500000, tax_rate=0.10)
تعریف تابع
def greet():
"""تابع سادهای که سلام میکند"""
print("سلام!")
# فراخوانی
greet() # سلام!
# با پارامتر
def greet_user(name):
print(f"سلام {name}!")
greet_user("علی") # سلام علی!
greet_user("زهرا") # سلام زهرا!
# با مقدار بازگشتی
def square(x):
return x ** 2
result = square(5) # 25
print(square(7)) # 49
Docstring
توضیح تابع با رشته سهگانه – مهم برای کد حرفهای:
def calculate_bmi(weight, height):
"""محاسبه شاخص توده بدنی (BMI).
Args:
weight (float): وزن به کیلوگرم
height (float): قد به متر
Returns:
float: شاخص BMI
Examples:
>>> calculate_bmi(70, 1.75)
22.86
"""
return weight / (height ** 2)
# دسترسی به docstring
print(calculate_bmi.__doc__)
help(calculate_bmi)
انواع پارامتر
پارامترهای موقعیتی (Positional)
def divide(a, b):
return a / b
print(divide(10, 2)) # 5.0
print(divide(2, 10)) # 0.2 ← ترتیب مهم است!
آرگومانهای کلیدی (Keyword Arguments)
def create_user(name, age, city):
print(f"{name}, {age}, {city}")
# با کلید (ترتیب مهم نیست)
create_user(age=25, name="علی", city="کاشان")
create_user(name="زهرا", city="تهران", age=30)
مقادیر پیشفرض
def greet(name, greeting="سلام"):
print(f"{greeting} {name}!")
greet("علی") # سلام علی!
greet("زهرا", "درود") # درود زهرا!
greet("محمد", greeting="هی") # هی محمد!
⚠️ تله مقدار پیشفرض تغییرپذیر:
# غلط!
def add_item(item, items=[]): # ← این لیست بین فراخوانیها مشترک است!
items.append(item)
return items
print(add_item("a")) # ['a']
print(add_item("b")) # ['a', 'b'] ← لیست جدید نیست!
# درست
def add_item(item, items=None):
if items is None:
items = []
items.append(item)
return items
تعداد متغیر آرگومان: *args
def sum_all(*args):
"""مجموع هر تعداد عدد"""
return sum(args)
print(sum_all(1, 2, 3)) # 6
print(sum_all(1, 2, 3, 4, 5)) # 15
print(sum_all()) # 0
# args یک تاپل است
def show_args(*args):
print(type(args)) # <class 'tuple'>
for arg in args:
print(arg)
show_args("a", "b", "c")
آرگومانهای کلیدی متغیر: **kwargs
def create_profile(**kwargs):
"""ساخت پروفایل با هر تعداد ویژگی"""
for key, value in kwargs.items():
print(f"{key}: {value}")
create_profile(name="علی", age=25, city="کاشان")
# kwargs یک دیکشنری است
def show_kwargs(**kwargs):
print(type(kwargs)) # <class 'dict'>
print(kwargs)
show_kwargs(a=1, b=2, c=3)
ترکیب همه با هم
def complex_func(name, age=18, *args, **kwargs):
print(f"name={name}, age={age}")
print(f"args={args}")
print(f"kwargs={kwargs}")
complex_func("علی", 25, "extra1", "extra2", city="کاشان", job="dev")
# name=علی, age=25
# args=('extra1', 'extra2')
# kwargs={'city': 'کاشان', 'job': 'dev'}
Unpacking در فراخوانی
def add(a, b, c):
return a + b + c
# با لیست/تاپل
nums = [1, 2, 3]
print(add(*nums)) # 6 معادل add(1, 2, 3)
# با دیکشنری
params = {"a": 1, "b": 2, "c": 3}
print(add(**params)) # 6 معادل add(a=1, b=2, c=3)
return – بازگشت چند مقدار
def get_min_max(numbers):
return min(numbers), max(numbers)
# دریافت تاپل
result = get_min_max([3, 1, 4, 1, 5, 9])
print(result) # (1, 9)
# unpacking
low, high = get_min_max([3, 1, 4, 1, 5, 9])
print(low, high) # 1 9
# بدون return - یعنی None برمیگردد
def no_return():
print("سلام")
x = no_return()
print(x) # None
# return زودهنگام
def find_first_even(numbers):
for n in numbers:
if n % 2 == 0:
return n
return None # هیچ زوج نبود
حوزه (Scope)
x = 100 # متغیر سراسری (Global)
def my_func():
y = 50 # متغیر محلی (Local)
print(x) # دسترسی به سراسری OK
print(y) # 50
my_func()
# print(y) # NameError - y محلی است
# تغییر سراسری از داخل تابع
counter = 0
def increment():
global counter
counter += 1
increment()
increment()
print(counter) # 2
# nonlocal برای closure
def outer():
x = 10
def inner():
nonlocal x
x += 1
inner()
print(x) # 11
outer()
قاعده LEGB
پایتون متغیرها را به این ترتیب میگردد:
- Local – تابع جاری
- Enclosing – تابع بیرونی (در closure)
- Global – فایل/ماژول
- Built-in – پایتون
توابع لامبدا
تابع بینام تکخطی:
# تابع معمولی
def double(x):
return x * 2
# لامبدا معادل
double = lambda x: x * 2
print(double(5)) # 10
# با چند پارامتر
add = lambda a, b: a + b
print(add(3, 5)) # 8
# کاربرد رایج: در sort/filter/map
prices = [("A", 100), ("B", 50), ("C", 75)]
prices.sort(key=lambda x: x[1])
print(prices)
# [('B', 50), ('C', 75), ('A', 100)]
# با filter
nums = [1, 2, 3, 4, 5, 6, 7, 8]
evens = list(filter(lambda x: x % 2 == 0, nums))
print(evens) # [2, 4, 6, 8]
# با map
squared = list(map(lambda x: x**2, nums))
print(squared)
💡 توصیه:
لامبدا را برای توابع ساده تکخطی استفاده کنید. برای منطق پیچیده، تابع معمولی با def خواناتر است.
توابع توکار مهم
# map - اعمال تابع روی هر عضو
nums = [1, 2, 3, 4]
squared = list(map(lambda x: x**2, nums))
print(squared) # [1, 4, 9, 16]
# filter - فیلتر بر اساس شرط
positives = list(filter(lambda x: x > 0, [-2, -1, 0, 1, 2]))
print(positives) # [1, 2]
# reduce - کاهش به یک مقدار
from functools import reduce
product = reduce(lambda a, b: a * b, [1, 2, 3, 4, 5])
print(product) # 120
# sum, min, max, all, any
print(sum([1, 2, 3])) # 6
print(min([3, 1, 4])) # 1
print(max([3, 1, 4])) # 4
print(all([True, True, False])) # False
print(any([False, False, True])) # True
# sorted با key
words = ["python", "is", "awesome"]
sorted_by_len = sorted(words, key=len)
print(sorted_by_len) # ['is', 'python', 'awesome']
توابع بازگشتی
# فاکتوریل
def factorial(n):
if n <= 1:
return 1
return n * factorial(n - 1)
print(factorial(5)) # 120
# فیبوناچی
def fib(n):
if n <= 1:
return n
return fib(n - 1) + fib(n - 2)
for i in range(10):
print(fib(i), end=" ")
# 0 1 1 2 3 5 8 13 21 34
تمرین فصل
🏋️ تمرین ۱: تابعی بنویسید که عددی بگیرد و True برگرداند اگر اول است.
🏋️ تمرین ۲: تابعی بنویسید که لیستی از اعداد بگیرد و میانگین، انحراف معیار و واریانس را برگرداند.
🏋️ تمرین ۳: تابعی بنویسید که قیمت و تخفیف (بهصورت پارامتر کلیدی با مقدار پیشفرض ۰) بگیرد و قیمت نهایی را چاپ کند.
🏋️ تمرین ۴: با لامبدا، لیستی از کلمات را بر اساس طول مرتب کنید (نزولی).
جمعبندی
- تعریف تابع با
defو docstring - پارامترها: موقعیتی، کلیدی، پیشفرض،
*args،**kwargs - Unpacking با
*و**در فراخوانی - بازگشت چند مقدار با تاپل
- Scope: Local، Enclosing، Global، Built-in
- توابع لامبدا برای موارد ساده
- توابع توکار:
map،filter،reduce،sorted