🐍 آموزش جامع Python — پست ۸۱
ارسال تابع به تابع دیگر
در Python میتوانیم یک تابع را بهعنوان آرگومان به تابع دیگری ارسال کنیم.
این قابلیت یکی از ویژگیهای مهم توابع در Python است.
🔹 مثال ساده
خروجی:
اینجا:
خود تابع
🔹 تابع با آرگومان
خروجی:
در اینجا
⚠️ نکته مهم
این دو با هم فرق دارند:
ارسال تابع
اما:
ابتدا
🧠 خلاصه
🎯 تمرین
دو تابع بنویسید:
سپس:
خروجی مورد انتظار:
پست ۸۱ از دوره جامع Python 🐍
ارسال تابع به تابع دیگر
در Python میتوانیم یک تابع را بهعنوان آرگومان به تابع دیگری ارسال کنیم.
این قابلیت یکی از ویژگیهای مهم توابع در Python است.
🔹 مثال ساده
def greet():
return "Hello Python"
def execute(function):
print(function())
execute(greet)
خروجی:
Hello Python
اینجا:
execute(greet)
خود تابع
greet را ارسال کردهایم، نه نتیجه اجرای آن.🔹 تابع با آرگومان
def square(x):
return x * x
def calculate(function, number):
return function(number)
result = calculate(square, 5)
print(result)
خروجی:
25
در اینجا
calculate هر تابعی را که بتواند یک عدد دریافت کند، میتواند اجرا کند.⚠️ نکته مهم
این دو با هم فرق دارند:
calculate(square, 5)
ارسال تابع
squareاما:
calculate(square(5), 5)
ابتدا
square(5) اجرا میشود و نتیجه آن ارسال میشود؛ بنابراین در این مثال نوع آرگومان با چیزی که calculate انتظار دارد سازگار نیست.🧠 خلاصه
تابع میتواند:
• در متغیر ذخیره شود
• به تابع دیگری ارسال شود
• توسط تابع دیگری اجرا شود
🎯 تمرین
دو تابع بنویسید:
def double(x):
return x * 2
def apply(function, number):
# کامل کنید
سپس:
print(apply(double, 10))
خروجی مورد انتظار:
20
پست ۸۱ از دوره جامع Python 🐍
🐍 آموزش جامع Python — پست ۸۲
تابع کوتاه با
در Python میتوانیم برای کارهای ساده، تابعی کوتاه را با
🔹 ساختار
مثلاً:
خروجی:
این کد تقریباً معادل این است:
🔹 چند آرگومان
خروجی:
⚠️ نکته مهم
اگر منطق تابع پیچیده باشد، معمولاً
🔹 استفاده همراه با تابع دیگر
خروجی:
اینجا تابع
🧠 خلاصه
🎯 تمرین
یک
خروجی مورد انتظار:
پست ۸۲ از دوره جامع Python 🐍
تابع کوتاه با
lambdaدر Python میتوانیم برای کارهای ساده، تابعی کوتاه را با
lambda تعریف کنیم.🔹 ساختار
lambda arguments: expression
مثلاً:
square = lambda x: x * x
print(square(5))
خروجی:
25
این کد تقریباً معادل این است:
def square(x):
return x * x
🔹 چند آرگومان
add = lambda a, b: a + b
print(add(10, 5))
خروجی:
15
⚠️ نکته مهم
lambda برای توابع ساده و کوتاه مناسب است.اگر منطق تابع پیچیده باشد، معمولاً
def خواناتر و مناسبتر است.🔹 استفاده همراه با تابع دیگر
def calculate(function, number):
return function(number)
result = calculate(lambda x: x * 2, 10)
print(result)
خروجی:
20
اینجا تابع
lambda مستقیماً به calculate ارسال شده است.🧠 خلاصه
def → تعریف معمولی تابع
lambda → تعریف کوتاه یک تابع ساده
🎯 تمرین
یک
lambda بنویسید که عدد را به توان ۳ برساند:cube = ...
print(cube(4))
خروجی مورد انتظار:
64
پست ۸۲ از دوره جامع Python 🐍
🐍 آموزش جامع Python — پست ۸۳
اعمال یک تابع روی همه اعضا با
گاهی میخواهیم یک عملیات یکسان را روی تمام اعضای یک مجموعه انجام دهیم.
🔹 مثال ساده
خروجی:
تابع
🔹 با تابع معمولی
خروجی:
🔹 چرا
در Python 3،
برای تبدیل آن به لیست:
استفاده میکنیم.
⚠️ نکته مهم
خروجی:
🧠 خلاصه
یعنی تابع را روی اعضای
🎯 تمرین
خروجی را قبل از اجرا حدس بزنید.
پست ۸۳ از دوره جامع Python 🐍
اعمال یک تابع روی همه اعضا با
map()گاهی میخواهیم یک عملیات یکسان را روی تمام اعضای یک مجموعه انجام دهیم.
map() برای همین کار استفاده میشود.🔹 مثال ساده
numbers = [1, 2, 3, 4]
result = map(lambda x: x * 2, numbers)
print(list(result))
خروجی:
[2, 4, 6, 8]
تابع
lambda روی تکتک اعضای numbers اجرا شده است.🔹 با تابع معمولی
def square(x):
return x * x
numbers = [2, 3, 4, 5]
result = map(square, numbers)
print(list(result))
خروجی:
[4, 9, 16, 25]
🔹 چرا
list()؟در Python 3،
map() یک iterator برمیگرداند و نتیجهها را بهصورت مستقیم به شکل لیست نمایش نمیدهد.برای تبدیل آن به لیست:
list(result)
استفاده میکنیم.
⚠️ نکته مهم
map() داده اصلی را تغییر نمیدهد:numbers = [1, 2, 3]
result = list(map(lambda x: x * 10, numbers))
print(numbers)
print(result)
خروجی:
[1, 2, 3]
[10, 20, 30]
🧠 خلاصه
map(function, iterable)
یعنی تابع را روی اعضای
iterable اعمال کن.🎯 تمرین
numbers = [5, 10, 15, 20]
result = map(lambda x: x + 5, numbers)
print(list(result))
خروجی را قبل از اجرا حدس بزنید.
پست ۸۳ از دوره جامع Python 🐍
🐍 آموزش جامع Python — پست ۸۴
فیلتر کردن دادهها با
در پست قبل با
اما اگر بخواهیم فقط اعضایی را نگه داریم که یک شرط خاص را دارند، از
🔹 مثال ساده
خروجی:
تابع
اگر نتیجه
🔹 با تابع معمولی
خروجی:
🔹 تفاوت
مثلاً:
⚠️ نکته
🎯 تمرین
خروجی را قبل از اجرا حدس بزنید.
پست ۸۴ از دوره جامع Python 🐍
فیلتر کردن دادهها با
filter()در پست قبل با
map() آشنا شدیم که برای تبدیل اعضای یک مجموعه استفاده میشود.اما اگر بخواهیم فقط اعضایی را نگه داریم که یک شرط خاص را دارند، از
filter() استفاده میکنیم.🔹 مثال ساده
numbers = [1, 2, 3, 4, 5, 6]
result = filter(lambda x: x % 2 == 0, numbers)
print(list(result))
خروجی:
[2, 4, 6]
تابع
lambda برای هر عدد بررسی میکند که زوج است یا نه.اگر نتیجه
True باشد، آن مقدار در نتیجه باقی میماند.🔹 با تابع معمولی
def is_positive(x):
return x > 0
numbers = [-2, 0, 3, -1, 5]
result = filter(is_positive, numbers)
print(list(result))
خروجی:
[3, 5]
🔹 تفاوت
map() و filter()map() → مقدارها را تبدیل میکند
filter() → مقدارها را انتخاب یا حذف میکند
مثلاً:
numbers = [1, 2, 3, 4]
list(map(lambda x: x * 2, numbers))
# [2, 4, 6, 8]
list(filter(lambda x: x % 2 == 0, numbers))
# [2, 4]
⚠️ نکته
filter() هم مانند map() در Python 3 یک iterator برمیگرداند؛ بنابراین برای ساختن لیست میتوانیم از list() استفاده کنیم.🎯 تمرین
numbers = [10, 15, 20, 25, 30]
result = filter(lambda x: x >= 20, numbers)
print(list(result))
خروجی را قبل از اجرا حدس بزنید.
پست ۸۴ از دوره جامع Python 🐍
1
🐍 آموزش جامع Python — پست ۸۵
ترکیب
در دو پست قبل یاد گرفتیم:
حالا میتوانیم این دو را با هم ترکیب کنیم.
🔹 مثال
فرض کنید فقط اعداد زوج را میخواهیم و سپس آنها را دو برابر کنیم:
خروجی:
ابتدا:
🔹 چرا ترتیب مهم است؟
اگر ابتدا
ابتدا اعداد دو برابر میشوند:
سپس فقط اعداد بزرگتر از
پس ترتیب عملیات روی نتیجه تأثیر دارد.
🧠 خلاصه
میتوانیم خروجی یکی را بهعنوان ورودی دیگری استفاده کنیم.
🎯 تمرین
کدی بنویسید که:
اعداد بزرگتر از
سپس آنها را 3 برابر کند.
خروجی مورد انتظار:
پست ۸۵ از دوره جامع Python 🐍
ترکیب
map() و filter()در دو پست قبل یاد گرفتیم:
map() → تبدیل دادهها
filter() → فیلتر کردن دادهها
حالا میتوانیم این دو را با هم ترکیب کنیم.
🔹 مثال
فرض کنید فقط اعداد زوج را میخواهیم و سپس آنها را دو برابر کنیم:
numbers = [1, 2, 3, 4, 5, 6]
even_numbers = filter(lambda x: x % 2 == 0, numbers)
result = map(lambda x: x * 2, even_numbers)
print(list(result))
خروجی:
[4, 8, 12]
ابتدا:
[1, 2, 3, 4, 5, 6]
↓
filter()
↓
[2, 4, 6]
↓
map()
↓
[4, 8, 12]
🔹 چرا ترتیب مهم است؟
اگر ابتدا
map() انجام دهیم:numbers = [1, 2, 3, 4]
result = filter(
lambda x: x > 5,
map(lambda x: x * 2, numbers)
)
print(list(result))
ابتدا اعداد دو برابر میشوند:
[2, 4, 6, 8]
سپس فقط اعداد بزرگتر از
5 باقی میمانند:[6, 8]
پس ترتیب عملیات روی نتیجه تأثیر دارد.
🧠 خلاصه
filter() → انتخاب
map() → تبدیل
میتوانیم خروجی یکی را بهعنوان ورودی دیگری استفاده کنیم.
🎯 تمرین
کدی بنویسید که:
اعداد بزرگتر از
10 را انتخاب کند.سپس آنها را 3 برابر کند.
numbers = [5, 10, 15, 20, 25]
خروجی مورد انتظار:
[45, 60, 75]
پست ۸۵ از دوره جامع Python 🐍
1
🐍 آموزش جامع Python — پست ۸۶
ترکیب همه دادهها با
تا اینجا:
حالا
برای استفاده از آن باید
🔹 مثال ساده
خروجی:
نحوه محاسبه:
🔹 ضرب اعداد
خروجی:
چون:
🔹 مقدار اولیه
میتوانیم یک مقدار اولیه هم مشخص کنیم:
خروجی:
محاسبه:
⚠️ نکته مهم
اگر لیست خالی باشد و مقدار اولیه نداشته باشیم،
🧠 خلاصه
🎯 تمرین
با
خروجی را قبل از اجرا حدس بزنید.
پست ۸۶ از دوره جامع Python 🐍
ترکیب همه دادهها با
reduce()تا اینجا:
map() → تبدیل دادهها
filter() → فیلتر کردن دادهها
حالا
reduce() را یاد میگیریم.reduce() چند مقدار را بهصورت مرحلهای با یکدیگر ترکیب میکند تا در نهایت به یک مقدار برسد.برای استفاده از آن باید
reduce را از functools وارد کنیم.🔹 مثال ساده
from functools import reduce
numbers = [1, 2, 3, 4]
result = reduce(lambda a, b: a + b, numbers)
print(result)
خروجی:
10
نحوه محاسبه:
1 + 2 → 3
3 + 3 → 6
6 + 4 → 10
🔹 ضرب اعداد
from functools import reduce
numbers = [2, 3, 4]
result = reduce(lambda a, b: a * b, numbers)
print(result)
خروجی:
24
چون:
2 × 3 → 6
6 × 4 → 24
🔹 مقدار اولیه
میتوانیم یک مقدار اولیه هم مشخص کنیم:
from functools import reduce
numbers = [1, 2, 3]
result = reduce(lambda a, b: a + b, numbers, 10)
print(result)
خروجی:
16
محاسبه:
10 + 1 → 11
11 + 2 → 13
13 + 3 → 16
⚠️ نکته مهم
اگر لیست خالی باشد و مقدار اولیه نداشته باشیم،
reduce() نمیداند از چه مقداری شروع کند و خطا ایجاد میشود.🧠 خلاصه
map() → چند مقدار → چند مقدارِ تبدیلشده
filter() → چند مقدار → چند مقدارِ انتخابشده
reduce() → چند مقدار → یک مقدار
🎯 تمرین
با
reduce() مجموع اعداد زیر را محاسبه کنید:from functools import reduce
numbers = [5, 10, 15, 20]
result = reduce(lambda a, b: a + b, numbers)
print(result)
خروجی را قبل از اجرا حدس بزنید.
پست ۸۶ از دوره جامع Python 🐍
1
🐍 آموزش جامع Python — پست ۸۷
تابع تو در تو | Nested Function
در Python میتوانیم یک تابع را داخل تابع دیگری تعریف کنیم.
به این نوع تابع، Nested Function میگوییم.
🔹 مثال ساده
خروجی:
تابع
🔹 چرا تابع تو در تو؟
یکی از کاربردها، محدود کردن یک تابع کمکی به همان تابعی است که به آن نیاز دارد.
خروجی:
اینجا
🔹 تابع داخلی میتواند مقدار بیرونی را ببیند
خروجی:
تابع
⚠️ نکته مهم
این موضوع با
🧠 خلاصه
🎯 تمرین
تابعی به نام
تابع داخلی باید
پست ۸۷ از دوره جامع Python 🐍
تابع تو در تو | Nested Function
در Python میتوانیم یک تابع را داخل تابع دیگری تعریف کنیم.
به این نوع تابع، Nested Function میگوییم.
🔹 مثال ساده
def outer():
print("Outer function")
def inner():
print("Inner function")
inner()
outer()
خروجی:
Outer function
Inner function
تابع
inner داخل outer تعریف شده و در این مثال فقط از داخل outer قابل استفاده است.🔹 چرا تابع تو در تو؟
یکی از کاربردها، محدود کردن یک تابع کمکی به همان تابعی است که به آن نیاز دارد.
def calculate_total(price, tax):
def calculate_tax():
return price * tax
return price + calculate_tax()
print(calculate_total(100, 0.1))
خروجی:
110.0
اینجا
calculate_tax() فقط برای محاسبه داخل calculate_total() استفاده شده است.🔹 تابع داخلی میتواند مقدار بیرونی را ببیند
def outer():
message = "Hello"
def inner():
print(message)
inner()
outer()
خروجی:
Hello
تابع
inner میتواند متغیر موجود در تابع بیرونی را بخواند.⚠️ نکته مهم
این موضوع با
nonlocal که در پست ۷۹ دیدیم مرتبط است:خواندن متغیر بیرونی → بدون nonlocal
تغییر متغیر بیرونی → معمولاً با nonlocal
🧠 خلاصه
Nested Function
↓
تابع داخل تابع
↓
برای منطق کمکی و محدود به یک محدوده مفید است
🎯 تمرین
تابعی به نام
greet_user بنویسید که داخل آن تابع get_message قرار داشته باشد.تابع داخلی باید
"Hello Python" را برگرداند و تابع بیرونی آن را چاپ کند.پست ۸۷ از دوره جامع Python 🐍
1
🐍 آموزش جامع Python — پست ۸۸
Closure چیست؟
در پست قبل با تابعهای تودرتو آشنا شدیم.
حالا یک قابلیت مهمتر را بررسی میکنیم: Closure.
Closure زمانی ایجاد میشود که یک تابع داخلی، متغیرهای تابع بیرونی را به خاطر بسپارد؛ حتی بعد از تمام شدن اجرای تابع بیرونی.
🔹 مثال ساده
خروجی:
اینجا
🔹 یک مثال کاربردی
خروجی:
هر تابع مقدار
⚠️ نکته مهم
در Closure، تابع داخلی فقط یک تابع ساده نیست؛ بلکه همراه با اطلاعاتی از محیطی که در آن ساخته شده باقی میماند.
🧠 خلاصه
🎯 تمرین
تابعی به نام
خروجی مورد انتظار:
پست ۸۸ از دوره جامع Python 🐍
Closure چیست؟
در پست قبل با تابعهای تودرتو آشنا شدیم.
حالا یک قابلیت مهمتر را بررسی میکنیم: Closure.
Closure زمانی ایجاد میشود که یک تابع داخلی، متغیرهای تابع بیرونی را به خاطر بسپارد؛ حتی بعد از تمام شدن اجرای تابع بیرونی.
🔹 مثال ساده
def create_greeting(name):
def greet():
return f"Hello {name}"
return greet
message = create_greeting("Ali")
print(message())
خروجی:
Hello Ali
اینجا
create_greeting() تمام شده، اما تابع greet هنوز مقدار name را در دسترس دارد.🔹 یک مثال کاربردی
def multiplier(factor):
def multiply(number):
return number * factor
return multiply
double = multiplier(2)
triple = multiplier(3)
print(double(5))
print(triple(5))
خروجی:
10
15
هر تابع مقدار
factor مربوط به خودش را به خاطر سپرده است.multiplier(2)
↓
double
↓
factor = 2
multiplier(3)
↓
triple
↓
factor = 3
⚠️ نکته مهم
در Closure، تابع داخلی فقط یک تابع ساده نیست؛ بلکه همراه با اطلاعاتی از محیطی که در آن ساخته شده باقی میماند.
🧠 خلاصه
Nested Function
→ تابع داخل تابع
Closure
→ تابع داخلی + دسترسی حفظشده به متغیرهای محیط بیرونی
🎯 تمرین
تابعی به نام
power بسازید که یک توان دریافت کند و یک تابع برگرداند:square = power(2)
print(square(5))
خروجی مورد انتظار:
25
پست ۸۸ از دوره جامع Python 🐍
1
🐍 آموزش جامع Python — پست ۸۹
تغییر رفتار تابع با
در پستهای قبل دیدیم که میتوانیم تابع را به تابع دیگری ارسال کنیم.
حالا از همین قابلیت برای ساخت Decorator استفاده میکنیم.
Decorator به ما اجازه میدهد بدون تغییر مستقیم کد یک تابع، رفتار آن را گسترش یا تغییر دهیم.
🔹 مثال ساده
حالا میتوانیم آن را روی یک تابع اعمال کنیم:
خروجی:
در واقع:
تابع اصلی را با تابع
🔹 استفاده از
Python برای Decorator یک syntax سادهتر دارد:
نتیجه همان است.
این:
تقریباً معادل این است:
⚠️ نکته مهم
Decorator خودش تابعی است که یک تابع را دریافت میکند و معمولاً تابع دیگری برمیگرداند.
🎯 تمرین
یک Decorator به نام
سپس آن را روی تابع زیر اعمال کنید:
خروجی مورد انتظار:
پست ۸۹ از دوره جامع Python 🐍
تغییر رفتار تابع با
Decoratorدر پستهای قبل دیدیم که میتوانیم تابع را به تابع دیگری ارسال کنیم.
حالا از همین قابلیت برای ساخت Decorator استفاده میکنیم.
Decorator به ما اجازه میدهد بدون تغییر مستقیم کد یک تابع، رفتار آن را گسترش یا تغییر دهیم.
🔹 مثال ساده
def logger(function):
def wrapper():
print("Function started")
function()
print("Function finished")
return wrapper
حالا میتوانیم آن را روی یک تابع اعمال کنیم:
def greet():
print("Hello Python")
greet = logger(greet)
greet()
خروجی:
Function started
Hello Python
Function finished
در واقع:
greet = logger(greet)
تابع اصلی را با تابع
wrapper جایگزین میکند.🔹 استفاده از
@Python برای Decorator یک syntax سادهتر دارد:
def logger(function):
def wrapper():
print("Function started")
function()
print("Function finished")
return wrapper
@logger
def greet():
print("Hello Python")
greet()
نتیجه همان است.
این:
@logger
def greet():
...
تقریباً معادل این است:
def greet():
...
greet = logger(greet)
⚠️ نکته مهم
Decorator خودش تابعی است که یک تابع را دریافت میکند و معمولاً تابع دیگری برمیگرداند.
function
↓
Decorator
↓
wrapper
↓
تابع با رفتار جدید
🎯 تمرین
یک Decorator به نام
before بنویسید که قبل از اجرای تابع، عبارت زیر را چاپ کند:Starting...
سپس آن را روی تابع زیر اعمال کنید:
@before
def hello():
print("Hello!")
خروجی مورد انتظار:
Starting...
Hello!
پست ۸۹ از دوره جامع Python 🐍
1
🐍 آموزش جامع Python — پست ۹۰
Decorator برای توابع دارای آرگومان
در پست قبل یک Decorator ساده ساختیم که روی تابعی بدون آرگومان کار میکرد.
اما در عمل، توابع معمولاً آرگومان دارند.
برای اینکه Decorator بتواند با انواع مختلف تابعها کار کند، از
🔹 مثال
حالا:
خروجی:
🔹 چرا
در اینجا:
و:
آنها را دوباره به تابع اصلی ارسال میکند.
🔹 چرا
برای آرگومانهای نامدار:
همه آنها را به تابع اصلی منتقل میکند.
⚠️ نکته مهم
اگر مقدار بازگشتی تابع اصلی را برنگردانیم، نتیجه تابع ممکن است از بین برود.
پس معمولاً در Decorator مینویسیم:
🧠 خلاصه
🎯 تمرین
Decorator زیر را کامل کنید:
سپس آن را روی تابع زیر امتحان کنید:
خروجی مورد انتظار:
پست ۹۰ از دوره جامع Python 🐍
Decorator برای توابع دارای آرگومان
در پست قبل یک Decorator ساده ساختیم که روی تابعی بدون آرگومان کار میکرد.
اما در عمل، توابع معمولاً آرگومان دارند.
برای اینکه Decorator بتواند با انواع مختلف تابعها کار کند، از
*args و **kwargs استفاده میکنیم.🔹 مثال
def logger(function):
def wrapper(*args, **kwargs):
print("Function started")
result = function(*args, **kwargs)
print("Function finished")
return result
return wrapper
حالا:
@logger
def add(a, b):
return a + b
result = add(10, 5)
print(result)
خروجی:
Function started
Function finished
15
🔹 چرا
*args؟*args آرگومانهای موقعیتی را دریافت میکند:add(10, 5)
در اینجا:
args → (10, 5)
و:
function(*args)
آنها را دوباره به تابع اصلی ارسال میکند.
🔹 چرا
**kwargs؟برای آرگومانهای نامدار:
@logger
def greet(name, language="English"):
return f"{name} - {language}"
print(greet(name="Ali", language="Persian"))
kwargs آرگومانهای نامدار را دریافت میکند و:function(*args, **kwargs)
همه آنها را به تابع اصلی منتقل میکند.
⚠️ نکته مهم
اگر مقدار بازگشتی تابع اصلی را برنگردانیم، نتیجه تابع ممکن است از بین برود.
پس معمولاً در Decorator مینویسیم:
result = function(*args, **kwargs)
return result
🧠 خلاصه
*args → آرگومانهای موقعیتی
**kwargs → آرگومانهای نامدار
function(*args, **kwargs)
→ ارسال دوباره آرگومانها به تابع اصلی
🎯 تمرین
Decorator زیر را کامل کنید:
def logger(function):
def wrapper(*args, **kwargs):
print("Starting...")
# تابع اصلی را اجرا کنید
# نتیجه را برگردانید
return wrapper
سپس آن را روی تابع زیر امتحان کنید:
@logger
def multiply(a, b):
return a * b
print(multiply(4, 5))
خروجی مورد انتظار:
Starting...
20
پست ۹۰ از دوره جامع Python 🐍
1
🐍 آموزش جامع Python — پست ۹۱
حفظ مشخصات تابع با
در پستهای قبل یاد گرفتیم چگونه Decorator بسازیم.
اما یک مشکل مهم وجود دارد:
وقتی یک تابع را با Decorator میپیچیم، ممکن است اطلاعات اصلی تابع مثل نام و توضیحات آن با اطلاعات
🔹 مثال
خروجی معمولاً:
یعنی مشخصات تابع اصلی از دست رفتهاند.
🔹 راهحل:
از
حالا:
خروجی:
🔹
این Decorator اطلاعات مهم تابع اصلی را روی
بنابراین بهتر است هنگام ساخت Decoratorهای واقعی، معمولاً از
🧠 خلاصه
🎯 تمرین
Decorator زیر را طوری کامل کنید که نام تابع اصلی حفظ شود:
سپس بررسی کنید:
پست ۹۱ از دوره جامع Python 🐍
حفظ مشخصات تابع با
functools.wrapsدر پستهای قبل یاد گرفتیم چگونه Decorator بسازیم.
اما یک مشکل مهم وجود دارد:
وقتی یک تابع را با Decorator میپیچیم، ممکن است اطلاعات اصلی تابع مثل نام و توضیحات آن با اطلاعات
wrapper جایگزین شود.🔹 مثال
def logger(function):
def wrapper(*args, **kwargs):
return function(*args, **kwargs)
return wrapper
@logger
def greet():
"""Say hello to the user."""
return "Hello"
print(greet.__name__)
print(greet.__doc__)
خروجی معمولاً:
wrapper
None
یعنی مشخصات تابع اصلی از دست رفتهاند.
🔹 راهحل:
wrapsاز
functools، ابزار wraps را وارد میکنیم:from functools import wraps
def logger(function):
@wraps(function)
def wrapper(*args, **kwargs):
return function(*args, **kwargs)
return wrapper
حالا:
@logger
def greet():
"""Say hello to the user."""
return "Hello"
print(greet.__name__)
print(greet.__doc__)
خروجی:
greet
Say hello to the user.
🔹
@wraps(function) چه میکند؟این Decorator اطلاعات مهم تابع اصلی را روی
wrapper حفظ میکند؛ از جمله اطلاعاتی مانند:__name__
__doc__
بنابراین بهتر است هنگام ساخت Decoratorهای واقعی، معمولاً از
@wraps(function) استفاده کنیم.🧠 خلاصه
Decorator
↓
wrapper
↓
@wraps(function)
↓
حفظ اطلاعات تابع اصلی
🎯 تمرین
Decorator زیر را طوری کامل کنید که نام تابع اصلی حفظ شود:
from functools import wraps
def my_decorator(function):
@wraps(function)
def wrapper(*args, **kwargs):
return function(*args, **kwargs)
return wrapper
سپس بررسی کنید:
@my_decorator
def hello():
"""Hello function"""
return "Hello"
print(hello.__name__)
print(hello.__doc__)
پست ۹۱ از دوره جامع Python 🐍
🐍 آموزش جامع Python — پست ۹۲
استفاده از چند Decorator برای یک تابع
در Python میتوانیم بیش از یک Decorator را روی یک تابع قرار دهیم.
این کار زمانی مفید است که بخواهیم چند رفتار مستقل را به یک تابع اضافه کنیم.
🔹 مثال ساده
خروجی:
🔹 ترتیب Decoratorها مهم است
وقتی مینویسیم:
Python آن را تقریباً مانند این در نظر میگیرد:
یعنی Decoratorها از پایین به بالا اعمال میشوند:
پس ابتدا
🔹 اما هنگام اجرای تابع چه اتفاقی میافتد؟
وقتی مینویسیم:
اجرای Wrapperها از بالا به پایین وارد میشود:
مثلاً:
خروجی:
چرا؟
چون ابتدا
سپس داخل آن:
اجرا میشود که در اینجا همان
بعد
و بعد از تمام شدن تابع اصلی:
🧠 یک قانون مهم برای حفظ کردن
اگر داشته باشیم:
ترتیب اعمال Decoratorها:
اما هنگام اجرای تابع، ورود به Wrapperها:
و هنگام خروج، ترتیب برعکس میشود:
به همین دلیل Decoratorها شبیه لایههای تو در تو عمل میکنند.
🔹 مثال کاربردی
میتوانیم یک Decorator برای ثبت اجرا و یکی برای بررسی دسترسی داشته باشیم:
خروجی:
چون:
⚠️ نکته مهم
جای Decoratorها را نمیتوان همیشه بدون تغییر نتیجه جابهجا کرد.
مثلاً:
لزوماً با:
رفتار یکسانی ندارد.
پس ترتیب Decoratorها بخشی از منطق برنامه است.
🧠 خلاصه
تقریباً معادل:
بنابراین:
🎯 تمرین
دو Decorator بسازید:
سپس هر دو را روی این تابع قرار دهید:
ترتیب خروجی را قبل از اجرا حدس بزنید.
پست ۹۲ از دوره جامع Python 🐍
استفاده از چند Decorator برای یک تابع
در Python میتوانیم بیش از یک Decorator را روی یک تابع قرار دهیم.
این کار زمانی مفید است که بخواهیم چند رفتار مستقل را به یک تابع اضافه کنیم.
🔹 مثال ساده
from functools import wraps
def first(function):
@wraps(function)
def wrapper():
print("First")
function()
return wrapper
def second(function):
@wraps(function)
def wrapper():
print("Second")
function()
return wrapper
@first
@second
def hello():
print("Hello")
hello()
خروجی:
First
Second
Hello
🔹 ترتیب Decoratorها مهم است
وقتی مینویسیم:
@first
@second
def hello():
...
Python آن را تقریباً مانند این در نظر میگیرد:
hello = first(second(hello))
یعنی Decoratorها از پایین به بالا اعمال میشوند:
hello اصلی
↓
second
↓
first
پس ابتدا
second تابع hello را میگیرد و سپس نتیجه آن به first داده میشود.🔹 اما هنگام اجرای تابع چه اتفاقی میافتد؟
وقتی مینویسیم:
hello()
اجرای Wrapperها از بالا به پایین وارد میشود:
first.wrapper
↓
second.wrapper
↓
hello اصلی
مثلاً:
def first(function):
def wrapper():
print("First START")
function()
print("First END")
return wrapper
def second(function):
def wrapper():
print("Second START")
function()
print("Second END")
return wrapper
@first
@second
def hello():
print("Hello")
hello()
خروجی:
First START
Second START
Hello
Second END
First END
چرا؟
چون ابتدا
first.wrapper اجرا میشود:First START
سپس داخل آن:
function()
اجرا میشود که در اینجا همان
second.wrapper است:Second START
بعد
second.wrapper تابع اصلی را اجرا میکند:Hello
و بعد از تمام شدن تابع اصلی:
Second END
First END
🧠 یک قانون مهم برای حفظ کردن
اگر داشته باشیم:
@A
@B
@C
def function():
...
ترتیب اعمال Decoratorها:
C → B → A
اما هنگام اجرای تابع، ورود به Wrapperها:
A → B → C → function
و هنگام خروج، ترتیب برعکس میشود:
function → C → B → A
به همین دلیل Decoratorها شبیه لایههای تو در تو عمل میکنند.
🔹 مثال کاربردی
میتوانیم یک Decorator برای ثبت اجرا و یکی برای بررسی دسترسی داشته باشیم:
from functools import wraps
def log(function):
@wraps(function)
def wrapper(*args, **kwargs):
print("Function called")
return function(*args, **kwargs)
return wrapper
def check_access(function):
@wraps(function)
def wrapper(*args, **kwargs):
print("Access checked")
return function(*args, **kwargs)
return wrapper
@log
@check_access
def delete_file():
print("File deleted")
delete_file()
خروجی:
Function called
Access checked
File deleted
چون:
delete_file = log(check_access(delete_file))
⚠️ نکته مهم
جای Decoratorها را نمیتوان همیشه بدون تغییر نتیجه جابهجا کرد.
مثلاً:
@first
@second
لزوماً با:
@second
@first
رفتار یکسانی ندارد.
پس ترتیب Decoratorها بخشی از منطق برنامه است.
🧠 خلاصه
@first
@second
def hello():
...
تقریباً معادل:
hello = first(second(hello))
بنابراین:
اعمال Decorator → از پایین به بالا
ورود به Wrapperها → از بالا به پایین
خروج از Wrapperها → از پایین به بالا
🎯 تمرین
دو Decorator بسازید:
before → قبل از اجرای تابع "Before" چاپ کند.after → بعد از اجرای تابع "After" چاپ کند.سپس هر دو را روی این تابع قرار دهید:
def hello():
print("Hello")
ترتیب خروجی را قبل از اجرا حدس بزنید.
پست ۹۲ از دوره جامع Python 🐍
🐍 آموزش جامع Python — پست ۹۳
Decorator عمومی با
در پست ۹۰ یاد گرفتیم چگونه با
حالا یک نکته مهمتر را میبینیم: یک Decorator عمومی میتواند روی تابعهایی با تعداد و نوع آرگومانهای متفاوت کار کند.
🔹 یک Decorator برای چند تابع
حالا همین Decorator را روی چند تابع متفاوت استفاده میکنیم:
خروجی:
🔹 نقش
در این مثال:
مثلاً:
یا:
یا:
و سپس:
همان آرگومانها را به تابع اصلی منتقل میکند.
🧠 چرا این موضوع مهم است؟
بدون
اما با این الگو:
میتوانیم یک Decorator عمومی داشته باشیم.
⚠️ نکته
این Decorator فقط به دلیل
🎯 تمرین
Decorator
سپس هر سه تابع را با آرگومانهای مختلف اجرا کنید.
پست ۹۳ از دوره جامع Python 🐍
Decorator عمومی با
*args و **kwargsدر پست ۹۰ یاد گرفتیم چگونه با
*args و **kwargs یک Decorator را برای تابعهای دارای آرگومان آماده کنیم.حالا یک نکته مهمتر را میبینیم: یک Decorator عمومی میتواند روی تابعهایی با تعداد و نوع آرگومانهای متفاوت کار کند.
🔹 یک Decorator برای چند تابع
from functools import wraps
def logger(function):
@wraps(function)
def wrapper(*args, **kwargs):
print("Function started")
result = function(*args, **kwargs)
print("Function finished")
return result
return wrapper
حالا همین Decorator را روی چند تابع متفاوت استفاده میکنیم:
@logger
def greet(name):
return f"Hello {name}"
@logger
def add(a, b):
return a + b
@logger
def welcome(name, language="English"):
return f"{name} - {language}"
print(greet("Ali"))
print(add(10, 5))
print(welcome("Sara", language="Persian"))
خروجی:
Function started
Function finished
Hello Ali
Function started
Function finished
15
Function started
Function finished
Sara - Persian
🔹 نقش
*args و **kwargsدر این مثال:
def wrapper(*args, **kwargs):
wrapper میتواند آرگومانهای مختلفی دریافت کند.مثلاً:
greet("Ali")یا:
add(10, 5)
یا:
welcome("Sara", language="Persian")و سپس:
function(*args, **kwargs)
همان آرگومانها را به تابع اصلی منتقل میکند.
🧠 چرا این موضوع مهم است؟
بدون
*args و **kwargs ممکن بود مجبور شویم برای هر نوع تابع، Decorator متفاوتی بنویسیم.اما با این الگو:
تابع با ۱ آرگومان ─┐
تابع با ۲ آرگومان ─┼→ یک Decorator
تابع با آرگومان نامدار ─┘
میتوانیم یک Decorator عمومی داشته باشیم.
⚠️ نکته
این Decorator فقط به دلیل
*args و **kwargs عمومی شده است؛ اما منطق داخل Decorator هنوز باید با هدف آن سازگار باشد.🎯 تمرین
Decorator
logger را روی این سه تابع امتحان کنید:@logger
def square(x):
return x * x
@logger
def multiply(a, b):
return a * b
@logger
def greet(name, message="Hello"):
return f"{message}, {name}"
سپس هر سه تابع را با آرگومانهای مختلف اجرا کنید.
پست ۹۳ از دوره جامع Python 🐍
🐍 آموزش جامع Python — پست ۹۴
ساخت Decorator با پارامتر
تا اینجا Decoratorهایی ساختیم که مستقیماً یک تابع را دریافت میکردند.
اما گاهی میخواهیم خود Decorator هم تنظیمات یا پارامتر دریافت کند.
مثلاً مشخص کنیم چند بار یک تابع اجرا شود.
🔹 مثال
میخواهیم Decoratorای بسازیم که تابع را به تعداد مشخص اجرا کند:
حالا:
خروجی:
🔹 اینجا چند لایه داریم
در:
ابتدا:
سپس
در نهایت
🔹 یک مثال دیگر
میتوانیم پیام دلخواه را به Decorator بدهیم:
خروجی:
⚠️ نکته مهم
Decorator معمولی:
یک تابع را دریافت میکند.
اما Decorator دارای پارامتر:
ابتدا پارامتر را دریافت میکند و سپس Decorator ساخته میشود.
به همین دلیل یک لایه تابع بیشتر داریم.
🧠 خلاصه
ساختار کلی:
🎯 تمرین
Decoratorای به نام
خروجی باید
پست ۹۴ از دوره جامع Python 🐍
ساخت Decorator با پارامتر
تا اینجا Decoratorهایی ساختیم که مستقیماً یک تابع را دریافت میکردند.
اما گاهی میخواهیم خود Decorator هم تنظیمات یا پارامتر دریافت کند.
مثلاً مشخص کنیم چند بار یک تابع اجرا شود.
🔹 مثال
میخواهیم Decoratorای بسازیم که تابع را به تعداد مشخص اجرا کند:
from functools import wraps
def repeat(times):
def decorator(function):
@wraps(function)
def wrapper(*args, **kwargs):
for _ in range(times):
function(*args, **kwargs)
return wrapper
return decorator
حالا:
@repeat(3)
def hello():
print("Hello")
hello()
خروجی:
Hello
Hello
Hello
🔹 اینجا چند لایه داریم
در:
@repeat(3)
def hello():
...
ابتدا:
repeat(3)
↓
decorator
↓
wrapper
↓
hello
repeat(3) تنظیمات Decorator را مشخص میکند.سپس
decorator تابع hello را دریافت میکند.در نهایت
wrapper هنگام اجرای hello() اجرا میشود.🔹 یک مثال دیگر
میتوانیم پیام دلخواه را به Decorator بدهیم:
def message(text):
def decorator(function):
@wraps(function)
def wrapper(*args, **kwargs):
print(text)
return function(*args, **kwargs)
return wrapper
return decorator
@message("Starting...")
def greet(name):
print(f"Hello {name}")
greet("Ali")
خروجی:
Starting...
Hello Ali
⚠️ نکته مهم
Decorator معمولی:
@logger
یک تابع را دریافت میکند.
اما Decorator دارای پارامتر:
@repeat(3)
ابتدا پارامتر را دریافت میکند و سپس Decorator ساخته میشود.
به همین دلیل یک لایه تابع بیشتر داریم.
🧠 خلاصه
@logger
→ Decorator معمولی
@repeat(3)
→ Decorator دارای پارامتر
ساختار کلی:
repeat(3)
↓
decorator(function)
↓
wrapper(*args, **kwargs)
🎯 تمرین
Decoratorای به نام
repeat بسازید که تعداد اجرا را دریافت کند:@repeat(5)
def hello():
print("Python")
خروجی باید
"Python" را ۵ بار چاپ کند.پست ۹۴ از دوره جامع Python 🐍
🐍 آموزش جامع Python — پست ۹۵
ترکیب Decorator معمولی و پارامتردار
حالا که هم Decorator معمولی و هم Decorator دارای پارامتر را میشناسیم، میتوانیم آنها را روی یک تابع با هم استفاده کنیم.
🔹 مثال
حالا:
خروجی:
🔹 ترتیب اعمال
این:
تقریباً معادل است با:
پس هنگام اعمال Decoratorها از پایین به بالا حرکت میکنیم:
اما هنگام اجرای تابع:
🔹 اگر ترتیب را عوض کنیم
اگر بنویسیم:
ساختار تغییر میکند:
در نتیجه خروجی:
چون این بار
⚠️ نکته مهم
دو Decorator ممکن است هر دو درست باشند، اما جابهجایی آنها میتواند رفتار برنامه را تغییر دهد.
بنابراین همیشه به این دو سؤال توجه کنید:
🧠 خلاصه
تقریباً:
بنابراین:
🎯 تمرین
با استفاده از
و:
قبل از اجرا، تفاوت تعداد دفعات
پست ۹۵ از دوره جامع Python 🐍
ترکیب Decorator معمولی و پارامتردار
حالا که هم Decorator معمولی و هم Decorator دارای پارامتر را میشناسیم، میتوانیم آنها را روی یک تابع با هم استفاده کنیم.
🔹 مثال
from functools import wraps
def log(function):
@wraps(function)
def wrapper(*args, **kwargs):
print("Function called")
return function(*args, **kwargs)
return wrapper
def repeat(times):
def decorator(function):
@wraps(function)
def wrapper(*args, **kwargs):
for _ in range(times):
function(*args, **kwargs)
return wrapper
return decorator
حالا:
@log
@repeat(2)
def greet(name):
print(f"Hello {name}")
greet("Ali")
خروجی:
Function called
Hello Ali
Hello Ali
🔹 ترتیب اعمال
این:
@log
@repeat(2)
def greet(name):
...
تقریباً معادل است با:
greet = log(repeat(2)(greet))
پس هنگام اعمال Decoratorها از پایین به بالا حرکت میکنیم:
greet
↓
repeat(2)
↓
log
اما هنگام اجرای تابع:
log
↓
repeat
↓
greet
🔹 اگر ترتیب را عوض کنیم
اگر بنویسیم:
@repeat(2)
@log
def greet(name):
print(f"Hello {name}")
ساختار تغییر میکند:
greet
↓
log
↓
repeat
در نتیجه خروجی:
Function called
Hello Ali
Function called
Hello Ali
چون این بار
log داخل repeat قرار گرفته و همراه هر اجرای تکراری اجرا میشود.⚠️ نکته مهم
دو Decorator ممکن است هر دو درست باشند، اما جابهجایی آنها میتواند رفتار برنامه را تغییر دهد.
بنابراین همیشه به این دو سؤال توجه کنید:
۱. Decoratorها با چه ترتیبی اعمال میشوند؟
۲. هنگام اجرای تابع، کدام wrapper بیرونیتر است؟
🧠 خلاصه
@A
@B
def function():
...
تقریباً:
function = A(B(function))
بنابراین:
اعمال → B سپس A
اجرا → A سپس B سپس function
🎯 تمرین
با استفاده از
log و repeat، دو حالت زیر را بسازید:@log
@repeat(3)
def hello():
print("Hello")
و:
@repeat(3)
@log
def hello():
print("Hello")
قبل از اجرا، تفاوت تعداد دفعات
"Function called" را حدس بزنید.پست ۹۵ از دوره جامع Python 🐍
🐍 آموزش جامع Python — پست ۹۶
بررسی و تغییر مقدار بازگشتی با Decorator
تا اینجا دیدیم Decorator میتواند قبل یا بعد از اجرای تابع کاری انجام دهد.
اما میتوانیم مقدار بازگشتی تابع (
🔹 دریافت مقدار
حالا:
خروجی:
اینجا:
مقدار بازگشتی تابع اصلی را دریافت میکند.
🔹 تغییر مقدار بازگشتی
Decorator حتی میتواند مقدار
استفاده:
خروجی:
چون تابع اصلی
🔹 چرا
اگر تابع اصلی مقداری برگرداند، اما Wrapper آن مقدار را
مثلاً:
اگر تابع اصلی این باشد:
خروجی:
چون Wrapper فقط
پس اگر میخواهیم مقدار بازگشتی حفظ شود:
🧠 خلاصه
در یک Decorator میتوانیم:
مقدار بازگشتی تابع را دریافت کنیم، سپس:
آن را بررسی کنیم.
تغییر دهیم.
یا بدون تغییر برگردانیم.
مثلاً:
🎯 تمرین
Decorator زیر را کامل کن تا مقدار بازگشتی تابع را سه برابر کند:
سپس:
خروجی باید باشد:
پست ۹۶ از دوره جامع Python 🐍
بررسی و تغییر مقدار بازگشتی با Decorator
تا اینجا دیدیم Decorator میتواند قبل یا بعد از اجرای تابع کاری انجام دهد.
اما میتوانیم مقدار بازگشتی تابع (
return) را هم دریافت و بررسی یا تغییر دهیم.🔹 دریافت مقدار
returnfrom functools import wraps
def check_result(function):
@wraps(function)
def wrapper(*args, **kwargs):
result = function(*args, **kwargs)
print("Result:", result)
return result
return wrapper
حالا:
@check_result
def add(a, b):
return a + b
x = add(10, 5)
print(x)
خروجی:
Result: 15
15
اینجا:
result = function(*args, **kwargs)
مقدار بازگشتی تابع اصلی را دریافت میکند.
🔹 تغییر مقدار بازگشتی
Decorator حتی میتواند مقدار
return را تغییر دهد:from functools import wraps
def double_result(function):
@wraps(function)
def wrapper(*args, **kwargs):
result = function(*args, **kwargs)
return result * 2
return wrapper
استفاده:
@double_result
def add(a, b):
return a + b
print(add(10, 5))
خروجی:
30
چون تابع اصلی
15 برمیگرداند و Decorator آن را دو برابر میکند.🔹 چرا
return result مهم است؟اگر تابع اصلی مقداری برگرداند، اما Wrapper آن مقدار را
return نکند، مقدار نهایی None خواهد بود.مثلاً:
def decorator(function):
def wrapper():
result = function()
print(result)
return wrapper
اگر تابع اصلی این باشد:
@decorator
def get_number():
return 10
x = get_number()
print(x)
خروجی:
10
None
چون Wrapper فقط
print() کرده و مقدار را برنگردانده است.پس اگر میخواهیم مقدار بازگشتی حفظ شود:
return result
🧠 خلاصه
در یک Decorator میتوانیم:
result = function(*args, **kwargs)
مقدار بازگشتی تابع را دریافت کنیم، سپس:
آن را بررسی کنیم.
تغییر دهیم.
یا بدون تغییر برگردانیم.
مثلاً:
result = function(*args, **kwargs)
return result
🎯 تمرین
Decorator زیر را کامل کن تا مقدار بازگشتی تابع را سه برابر کند:
def triple_result(function):
def wrapper(*args, **kwargs):
result = function(*args, **kwargs)
# کد اینجا
return wrapper
سپس:
@triple_result
def multiply(a, b):
return a * b
print(multiply(4, 5))
خروجی باید باشد:
60
پست ۹۶ از دوره جامع Python 🐍
1
🐍 آموزش جامع Python — پست ۹۷
ساخت Decorator با کلاس |
تا اینجا Decoratorها را با تابع ساختیم.
در Python میتوانیم یک Decorator را با کلاس هم بسازیم.
برای این کار، کلاس باید متد ویژهی
🔹 مثال ساده
حالا:
خروجی:
🔹 چه اتفاقی افتاد؟
این:
تقریباً معادل است با:
بنابراین
وقتی مینویسیم:
Python متد:
را اجرا میکند.
🔹 Decorator کلاسی با
میتوانیم مقدار بازگشتی تابع را هم حفظ کنیم:
استفاده:
خروجی:
⚠️ نکته مهم
در Decoratorهای کلاسی،
و
🧠 خلاصه
ساختار کلی:
پس:
🎯 تمرین
یک Decorator کلاسی به نام
مثلاً:
خروجی:
پست ۹۷ از دوره جامع Python 🐍
ساخت Decorator با کلاس |
__call__تا اینجا Decoratorها را با تابع ساختیم.
در Python میتوانیم یک Decorator را با کلاس هم بسازیم.
برای این کار، کلاس باید متد ویژهی
__call__ را داشته باشد.🔹 مثال ساده
class MyDecorator:
def __init__(self, function):
self.function = function
def __call__(self):
print("Before")
self.function()
print("After")
حالا:
@MyDecorator
def hello():
print("Hello")
hello()
خروجی:
Before
Hello
After
🔹 چه اتفاقی افتاد؟
این:
@MyDecorator
def hello():
print("Hello")
تقریباً معادل است با:
hello = MyDecorator(hello)
بنابراین
hello دیگر مستقیماً تابع اصلی نیست؛ بلکه یک شیء از کلاس MyDecorator است.وقتی مینویسیم:
hello()
Python متد:
__call__()
را اجرا میکند.
🔹 Decorator کلاسی با
returnمیتوانیم مقدار بازگشتی تابع را هم حفظ کنیم:
class MyDecorator:
def __init__(self, function):
self.function = function
def __call__(self, a, b):
print("Calculating...")
result = self.function(a, b)
return result
استفاده:
@MyDecorator
def add(a, b):
return a + b
print(add(10, 5))
خروجی:
Calculating...
15
⚠️ نکته مهم
در Decoratorهای کلاسی،
__init__ معمولاً تابع اصلی را دریافت و ذخیره میکند:self.function = function
و
__call__ زمانی اجرا میشود که شیء Decorator را مانند تابع صدا بزنیم:add(10, 5)
🧠 خلاصه
ساختار کلی:
class Decorator:
def __init__(self, function):
self.function = function
def __call__(self, *args, **kwargs):
return self.function(*args, **kwargs)
پس:
__init__ → تابع را دریافت میکند.__call__ → هنگام اجرای تابع Decorated اجرا میشود.self.function → به تابع اصلی اشاره میکند.🎯 تمرین
یک Decorator کلاسی به نام
UpperCase بساز که مقدار بازگشتی یک تابع را به حروف بزرگ تبدیل کند.مثلاً:
@UpperCase
def message():
return "hello python"
خروجی:
HELLO PYTHON
پست ۹۷ از دوره جامع Python 🐍
1
🐍 آموزش جامع Python — پست ۹۸
استفاده از Decorator روی متدهای کلاس
حالا که Decoratorهای معمولی و کلاسی را میشناسیم، ببینیم چطور میتوانیم یک Decorator را روی متدهای یک کلاس استفاده کنیم.
🔹 مثال ساده
حالا آن را روی یک متد قرار میدهیم:
استفاده:
خروجی:
🔹
وقتی متد را اینطور اجرا میکنیم:
مقدار
به همین دلیل در Decorator بهتر است از:
استفاده کنیم تا Decorator بتواند متدهای مختلف را بدون وابستگی به تعداد آرگومانها مدیریت کند.
🔹 مثال کاربردی
فرض کنیم میخواهیم قبل از اجرای بعضی متدها پیام ثبت کنیم:
استفاده:
خروجی:
🔹 مثال کامل
حالا یک Decorator میسازیم که مقدار بازگشتی متد را دریافت و چاپ کند:
استفاده در کلاس:
حالا:
خروجی:
اینجا:
مقدار
سپس:
آن را نمایش میدهد.
و در نهایت:
باعث میشود مقدار
⚠️ نکته مهم
اگر این خط را حذف کنیم:
متد Decorated دیگر مقدار
🧠 خلاصه
Decorator میتواند روی:
توابع معمولی
متدهای کلاس
متدهای دارای آرگومان
استفاده شود.
برای متدهای کلاس، استفاده از:
باعث میشود Decorator انعطافپذیرتر باشد.
🎯 تمرین
Decorator زیر را کامل کن تا نام متد و نتیجهی آن را چاپ کند:
خروجی مورد انتظار:
پست ۹۸ از دوره جامع Python 🐍
استفاده از Decorator روی متدهای کلاس
حالا که Decoratorهای معمولی و کلاسی را میشناسیم، ببینیم چطور میتوانیم یک Decorator را روی متدهای یک کلاس استفاده کنیم.
🔹 مثال ساده
from functools import wraps
def log_call(function):
@wraps(function)
def wrapper(*args, **kwargs):
print("Method called")
return function(*args, **kwargs)
return wrapper
حالا آن را روی یک متد قرار میدهیم:
class Calculator:
@log_call
def add(self, a, b):
return a + b
استفاده:
calc = Calculator()
print(calc.add(10, 5))
خروجی:
Method called
15
🔹
self چه اتفاقی میافتد؟وقتی متد را اینطور اجرا میکنیم:
calc.add(10, 5)
مقدار
self به صورت خودکار به متد ارسال میشود.به همین دلیل در Decorator بهتر است از:
*args, **kwargs
استفاده کنیم تا Decorator بتواند متدهای مختلف را بدون وابستگی به تعداد آرگومانها مدیریت کند.
🔹 مثال کاربردی
فرض کنیم میخواهیم قبل از اجرای بعضی متدها پیام ثبت کنیم:
from functools import wraps
def log_call(function):
@wraps(function)
def wrapper(*args, **kwargs):
print(f"Calling {function.__name__}")
return function(*args, **kwargs)
return wrapper
class User:
@log_call
def login(self):
print("User logged in")
@log_call
def logout(self):
print("User logged out")
استفاده:
user = User()
user.login()
user.logout()
خروجی:
Calling login
User logged in
Calling logout
User logged out
🔹 مثال کامل
show_resultحالا یک Decorator میسازیم که مقدار بازگشتی متد را دریافت و چاپ کند:
from functools import wraps
def show_result(function):
@wraps(function)
def wrapper(*args, **kwargs):
result = function(*args, **kwargs)
print(f"Result: {result}")
return result
return wrapper
استفاده در کلاس:
class Calculator:
@show_result
def multiply(self, a, b):
return a * b
حالا:
calc = Calculator()
result = calc.multiply(4, 6)
print("Returned value:", result)
خروجی:
Result: 24
Returned value: 24
اینجا:
result = function(*args, **kwargs)
مقدار
24 را از متد اصلی دریافت میکند.سپس:
print(f"Result: {result}")آن را نمایش میدهد.
و در نهایت:
return result
باعث میشود مقدار
24 همچنان به کد اصلی برگردد.⚠️ نکته مهم
اگر این خط را حذف کنیم:
return result
متد Decorated دیگر مقدار
24 را به کد اصلی برنمیگرداند و نتیجهی calc.multiply(4, 6) برابر None خواهد شد.🧠 خلاصه
Decorator میتواند روی:
توابع معمولی
متدهای کلاس
متدهای دارای آرگومان
استفاده شود.
برای متدهای کلاس، استفاده از:
*args, **kwargs
باعث میشود Decorator انعطافپذیرتر باشد.
🎯 تمرین
Decorator زیر را کامل کن تا نام متد و نتیجهی آن را چاپ کند:
@show_result
def multiply(self, a, b):
return a * b
خروجی مورد انتظار:
multiply -> 24
پست ۹۸ از دوره جامع Python 🐍
1
🐍 آموزش جامع Python — پست ۹۹
متدهای Static در کلاس |
تا اینجا با متدهای معمولی کلاس آشنا شدیم؛ متدهایی که
اما گاهی متدی داریم که به هیچ شیء خاصی از کلاس نیاز ندارد.
در این حالت میتوانیم از
🔹 مثال ساده
میتوانیم بدون ساختن شیء از آن استفاده کنیم:
خروجی:
🔹 تفاوت با متد معمولی
متد معمولی:
برای استفاده:
اما
و میتوانیم مستقیماً بنویسیم:
🔹 آیا از طریق شیء هم میشود؟
بله:
خروجی:
اما نکته مهم این است که
🔹 مثال کاربردی
فرض کنیم کلاسی برای کار با کاربران داریم:
استفاده:
خروجی:
این متد به
⚠️ نکته مهم
بنابراین:
با این ساختار:
متفاوت است.
🧠 خلاصه
اگر یک متد:
به
به اطلاعات نمونهی کلاس وابسته نیست.
فقط یک عملیات مستقل مرتبط با کلاس انجام میدهد.
میتوانیم از:
استفاده کنیم.
مثلاً:
فراخوانی:
🎯 تمرین
کلاسی به نام
مثلاً:
خروجی:
پست ۹۹ از دوره جامع Python 🐍
متدهای Static در کلاس |
@staticmethodتا اینجا با متدهای معمولی کلاس آشنا شدیم؛ متدهایی که
self دریافت میکنند.اما گاهی متدی داریم که به هیچ شیء خاصی از کلاس نیاز ندارد.
در این حالت میتوانیم از
@staticmethod استفاده کنیم.🔹 مثال ساده
class Calculator:
@staticmethod
def add(a, b):
return a + b
میتوانیم بدون ساختن شیء از آن استفاده کنیم:
print(Calculator.add(10, 5))
خروجی:
15
🔹 تفاوت با متد معمولی
متد معمولی:
class Calculator:
def add(self, a, b):
return a + b
برای استفاده:
calc = Calculator()
print(calc.add(10, 5))
اما
staticmethod نیازی به self ندارد:class Calculator:
@staticmethod
def add(a, b):
return a + b
و میتوانیم مستقیماً بنویسیم:
Calculator.add(10, 5)
🔹 آیا از طریق شیء هم میشود؟
بله:
calc = Calculator()
print(calc.add(10, 5))
خروجی:
15
اما نکته مهم این است که
add() به اطلاعات داخل calc وابسته نیست.🔹 مثال کاربردی
فرض کنیم کلاسی برای کار با کاربران داریم:
class User:
@staticmethod
def is_valid_age(age):
return age >= 18
استفاده:
print(User.is_valid_age(20))
print(User.is_valid_age(15))
خروجی:
True
False
این متد به
self یا اطلاعات یک کاربر خاص نیاز ندارد؛ فقط یک مقدار دریافت میکند و نتیجه میدهد.⚠️ نکته مهم
@staticmethod باعث میشود Python هنگام فراخوانی متد، self را به صورت خودکار ارسال نکند.بنابراین:
@staticmethod
def add(a, b):
return a + b
با این ساختار:
def add(self, a, b):
متفاوت است.
🧠 خلاصه
اگر یک متد:
به
self نیاز ندارد.به اطلاعات نمونهی کلاس وابسته نیست.
فقط یک عملیات مستقل مرتبط با کلاس انجام میدهد.
میتوانیم از:
@staticmethod
استفاده کنیم.
مثلاً:
class Calculator:
@staticmethod
def add(a, b):
return a + b
فراخوانی:
Calculator.add(10, 5)
🎯 تمرین
کلاسی به نام
Math بساز و یک staticmethod به نام square ایجاد کن که مربع یک عدد را برگرداند.مثلاً:
print(Math.square(6))
خروجی:
36
پست ۹۹ از دوره جامع Python 🐍
1
🐍 آموزش جامع Python — پست ۱۰۰
متدهای Class در Python |
در پست قبل با
حالا نوع دیگری از متدها را یاد میگیریم:
این متد به جای
🔹 مثال ساده
استفاده:
خروجی:
اینجا
🔹 تغییر مقدار Class Attribute
حالا:
خروجی:
🔹 تفاوت
در متد معمولی:
اما در
🔹 یک کاربرد مهم: Alternative Constructor
یکی از کاربردهای رایج
حالا:
خروجی:
اینجا:
یک نمونهی جدید از کلاس ایجاد میکند.
⚠️ نکته مهم
سه حالت مهم را از هم جدا کن:
→ متد معمولی و مرتبط با نمونه
→ متد مرتبط با کلاس
→ متدی که به
🧠 خلاصه
نوع متد
پارامتر اصلی
وابستگی
معمولی
نمونه
کلاس
ندارد
مستقل
🎯 تمرین
کلاس زیر را کامل کن:
طوری بنویس که:
خروجی:
✅ پاسخ کامل تمرین
خروجی:
در این مثال:
رشته را به دو بخش تقسیم میکند:
سپس:
با استفاده از
پست ۱۰۰ از دوره جامع Python 🐍
متدهای Class در Python |
@classmethodدر پست قبل با
@staticmethod آشنا شدیم.حالا نوع دیگری از متدها را یاد میگیریم:
@classmethod.این متد به جای
self، یک پارامتر به نام cls دریافت میکند که به خود کلاس اشاره دارد.🔹 مثال ساده
class Person:
count = 0
@classmethod
def show_count(cls):
return cls.count
استفاده:
print(Person.show_count())
خروجی:
0
اینجا
cls به کلاس Person اشاره میکند.🔹 تغییر مقدار Class Attribute
class Person:
count = 0
@classmethod
def increase_count(cls):
cls.count += 1
حالا:
Person.increase_count()
Person.increase_count()
print(Person.count)
خروجی:
2
🔹 تفاوت
self و clsدر متد معمولی:
def method(self):
self به نمونهی کلاس اشاره میکند.اما در
classmethod:@classmethod
def method(cls):
cls به خود کلاس اشاره میکند.🔹 یک کاربرد مهم: Alternative Constructor
یکی از کاربردهای رایج
classmethod ساختن یک شیء با روش دیگری است.class Person:
def __init__(self, name, age):
self.name = name
self.age = age
@classmethod
def from_string(cls, data):
name, age = data.split(",")
return cls(name, int(age))
حالا:
person = Person.from_string("Ali,25")
print(person.name)
print(person.age)خروجی:
Ali
25
اینجا:
return cls(name, int(age))
یک نمونهی جدید از کلاس ایجاد میکند.
⚠️ نکته مهم
سه حالت مهم را از هم جدا کن:
def method(self):
→ متد معمولی و مرتبط با نمونه
@classmethod
def method(cls):
→ متد مرتبط با کلاس
@staticmethod
def method():
→ متدی که به
self و cls نیاز ندارد.🧠 خلاصه
نوع متد
پارامتر اصلی
وابستگی
معمولی
selfنمونه
classmethodclsکلاس
staticmethodندارد
مستقل
🎯 تمرین
کلاس زیر را کامل کن:
class Product:
def __init__(self, name, price):
self.name = name
self.price = price
@classmethod
def from_string(cls, data):
# کد اینجا
طوری بنویس که:
product = Product.from_string("Laptop,1200")
print(product.name)
print(product.price)خروجی:
Laptop
1200
✅ پاسخ کامل تمرین
class Product:
def __init__(self, name, price):
self.name = name
self.price = price
@classmethod
def from_string(cls, data):
name, price = data.split(",")
return cls(name, int(price))
product = Product.from_string("Laptop,1200")
print(product.name)
print(product.price)
خروجی:
Laptop
1200
در این مثال:
data.split(",")رشته را به دو بخش تقسیم میکند:
Laptop
1200
سپس:
return cls(name, int(price))
با استفاده از
cls یک شیء جدید از Product میسازد.پست ۱۰۰ از دوره جامع Python 🐍
1