🐍 آموزش جامع 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
🐍 آموزش جامع Python — پست ۱۰۱
کنترل دسترسی به ویژگیها با
در کلاسها معمولاً ویژگیها را مستقیماً از طریق شیء میخوانیم:
اما گاهی میخواهیم هنگام دسترسی به یک ویژگی، منطق خاصی اجرا شود.
برای این کار میتوانیم از
🔹 مثال ساده
حالا:
خروجی:
دقت کن که
نه مثل تابع:
🔹 چرا
بدون
و استفاده کنیم:
اما با
خواندن مقدار طبیعیتر و شبیه دسترسی به یک ویژگی معمولی است.
🔹 مثال کاربردی
استفاده:
خروجی:
هر بار که
⚠️ نکته مهم
متدی که با
نه:
🧠 خلاصه
سپس:
🎯 تمرین
کلاس زیر را کامل کن:
طوری بنویس که:
خروجی:
✅ پاسخ کامل تمرین
خروجی:
در اینجا:
قطر دایره را محاسبه میکند.
چون
و به دلیل استفاده از
پست ۱۰۱ از دوره جامع Python 🐍
کنترل دسترسی به ویژگیها با
@propertyدر کلاسها معمولاً ویژگیها را مستقیماً از طریق شیء میخوانیم:
class Person:
def __init__(self, name):
self.name = name
person = Person("Ali")
print(person.name)
اما گاهی میخواهیم هنگام دسترسی به یک ویژگی، منطق خاصی اجرا شود.
برای این کار میتوانیم از
@property استفاده کنیم.🔹 مثال ساده
class Person:
def __init__(self, first_name, last_name):
self.first_name = first_name
self.last_name = last_name
@property
def full_name(self):
return f"{self.first_name} {self.last_name}"
حالا:
person = Person("Ali", "Ahmadi")
print(person.full_name)خروجی:
Ali Ahmadi
دقت کن که
full_name را مثل ویژگی استفاده کردیم:person.full_name
نه مثل تابع:
person.full_name()
🔹 چرا
@property مفید است؟بدون
property ممکن بود مجبور شویم یک متد بنویسیم:def get_full_name(self):
return f"{self.first_name} {self.last_name}"
و استفاده کنیم:
person.get_full_name()
اما با
@property:person.full_name
خواندن مقدار طبیعیتر و شبیه دسترسی به یک ویژگی معمولی است.
🔹 مثال کاربردی
class Rectangle:
def __init__(self, width, height):
self.width = width
self.height = height
@property
def area(self):
return self.width * self.height
استفاده:
rectangle = Rectangle(10, 5)
print(rectangle.area)
خروجی:
50
هر بار که
rectangle.area را میخوانیم، مقدار مساحت محاسبه میشود.⚠️ نکته مهم
متدی که با
@property مشخص شده، هنگام استفاده بدون () فراخوانی میشود:rectangle.area
نه:
rectangle.area()
🧠 خلاصه
@property به ما اجازه میدهد یک متد را مانند یک ویژگی استفاده کنیم.@property
def area(self):
return self.width * self.height
سپس:
rectangle.area
🎯 تمرین
کلاس زیر را کامل کن:
class Circle:
def __init__(self, radius):
self.radius = radius
@property
def diameter(self):
# کد اینجا
طوری بنویس که:
circle = Circle(5)
print(circle.diameter)
خروجی:
10
✅ پاسخ کامل تمرین
class Circle:
def __init__(self, radius):
self.radius = radius
@property
def diameter(self):
return self.radius * 2
circle = Circle(5)
print(circle.diameter)
خروجی:
10
در اینجا:
return self.radius * 2
قطر دایره را محاسبه میکند.
چون
radius برابر 5 است:5 × 2 = 10
و به دلیل استفاده از
@property، برای دسترسی به diameter نیازی به () نداریم:circle.diameter
پست ۱۰۱ از دوره جامع Python 🐍
🐍 آموزش جامع Python — پست ۱۰۲
تغییر مقدار ویژگی با
در پست قبل یاد گرفتیم با
اما اگر بخواهیم هنگام تغییر مقدار هم کنترل داشته باشیم، میتوانیم از
🔹 مثال ساده
حالا:
خروجی:
🔹 چرا Setter مفید است؟
میتوانیم قبل از ذخیره مقدار، آن را اعتبارسنجی کنیم.
مثلاً سن نباید منفی باشد:
استفاده:
خروجی:
اما:
باعث خطای:
میشود.
🔹 چرا از
اگر داخل Setter بنویسیم:
Setter دوباره خودش را صدا میزند و وارد یک حلقهی بازگشتی میشود.
به همین دلیل مقدار اصلی را در ویژگی دیگری مانند:
ذخیره میکنیم.
🧠 خلاصه
Getter:
برای خواندن مقدار است.
Setter:
برای تغییر مقدار است.
به این ترتیب میتوانیم هنگام تغییر ویژگی، قوانین و اعتبارسنجیهای موردنظرمان را اجرا کنیم.
🎯 تمرین
کلاس
باید این کد:
خروجی:
و این کد:
خطای
✅ پاسخ کامل تمرین
خروجی:
اگر مقدار منفی وارد کنیم:
خروجی خطا خواهد بود:
در این مثال:
در
سپس Getter مقدار ذخیرهشده در:
را برمیگرداند.
پست ۱۰۲ از دوره جامع Python 🐍
تغییر مقدار ویژگی با
@property و Setterدر پست قبل یاد گرفتیم با
@property میتوانیم یک مقدار را مثل ویژگی بخوانیم.اما اگر بخواهیم هنگام تغییر مقدار هم کنترل داشته باشیم، میتوانیم از
setter استفاده کنیم.🔹 مثال ساده
class Person:
def __init__(self, age):
self._age = age
@property
def age(self):
return self._age
@age.setter
def age(self, value):
self._age = value
حالا:
person = Person(20)
print(person.age)
person.age = 25
print(person.age)
خروجی:
20
25
🔹 چرا Setter مفید است؟
میتوانیم قبل از ذخیره مقدار، آن را اعتبارسنجی کنیم.
مثلاً سن نباید منفی باشد:
class Person:
def __init__(self, age):
self.age = age
@property
def age(self):
return self._age
@age.setter
def age(self, value):
if value < 0:
raise ValueError("Age cannot be negative")
self._age = value
استفاده:
person = Person(20)
person.age = 30
print(person.age)
خروجی:
30
اما:
person.age = -5
باعث خطای:
ValueError: Age cannot be negative
میشود.
🔹 چرا از
_age استفاده کردیم؟اگر داخل Setter بنویسیم:
self.age = value
Setter دوباره خودش را صدا میزند و وارد یک حلقهی بازگشتی میشود.
به همین دلیل مقدار اصلی را در ویژگی دیگری مانند:
self._age
ذخیره میکنیم.
🧠 خلاصه
Getter:
@property
def age(self):
return self._age
برای خواندن مقدار است.
Setter:
@age.setter
def age(self, value):
self._age = value
برای تغییر مقدار است.
به این ترتیب میتوانیم هنگام تغییر ویژگی، قوانین و اعتبارسنجیهای موردنظرمان را اجرا کنیم.
🎯 تمرین
کلاس
Product را طوری کامل کن که قیمت محصول نمیتواند منفی باشد:class Product:
def __init__(self, price):
self.price = price
@property
def price(self):
# کد اینجا
@price.setter
def price(self, value):
# کد اینجا
باید این کد:
product = Product(100)
product.price = 150
print(product.price)
خروجی:
150
و این کد:
product.price = -20
خطای
ValueError ایجاد کند.✅ پاسخ کامل تمرین
class Product:
def __init__(self, price):
self.price = price
@property
def price(self):
return self._price
@price.setter
def price(self, value):
if value < 0:
raise ValueError("Price cannot be negative")
self._price = value
product = Product(100)
print(product.price)
product.price = 150
print(product.price)
خروجی:
100
150
اگر مقدار منفی وارد کنیم:
product.price = -20
خروجی خطا خواهد بود:
ValueError: Price cannot be negative
در این مثال:
self.price = price
در
__init__ باعث میشود Setter نیز برای مقدار اولیه اجرا شود.سپس Getter مقدار ذخیرهشده در:
self._price
را برمیگرداند.
پست ۱۰۲ از دوره جامع Python 🐍
🐍 آموزش جامع Python — پست ۱۰۳
حذف ویژگی با
در پست قبل یاد گرفتیم با
حالا میتوانیم عملیات حذف آن ویژگی را هم کنترل کنیم.
برای این کار از
🔹 مثال ساده
حالا:
قبل از حذف:
بعد از:
ویژگی
🔹 چرا Deleter مفید است؟
گاهی نمیخواهیم یک ویژگی بدون کنترل حذف شود.
مثلاً میتوانیم هنگام حذف، یک عملیات اضافی انجام دهیم:
استفاده:
خروجی:
🔹 سه بخش یک Property
حالا میتوانیم یک
اینجا:
🔹 استفاده
در اینجا هر سه عملیات توسط
⚠️ نکته مهم
بعد از:
دیگر
بنابراین اگر دوباره بنویسیم:
با خطای
🧠 خلاصه
یک
برای خواندن
برای تغییر
برای حذف
🎯 تمرین
کلاس
سپس این کد را اجرا کن:
پست ۱۰۳ از دوره جامع Python 🐍
حذف ویژگی با
@property و deleterدر پست قبل یاد گرفتیم با
setter میتوانیم تغییر مقدار یک ویژگی را کنترل کنیم.حالا میتوانیم عملیات حذف آن ویژگی را هم کنترل کنیم.
برای این کار از
@property همراه با deleter استفاده میکنیم.🔹 مثال ساده
class Person:
def __init__(self, name):
self._name = name
@property
def name(self):
return self._name
@name.deleter
def name(self):
del self._name
حالا:
person = Person("Ali")
print(person.name)
del person.nameقبل از حذف:
Ali
بعد از:
del person.name
ویژگی
_name از شیء حذف میشود.🔹 چرا Deleter مفید است؟
گاهی نمیخواهیم یک ویژگی بدون کنترل حذف شود.
مثلاً میتوانیم هنگام حذف، یک عملیات اضافی انجام دهیم:
class User:
def __init__(self, username):
self._username = username
@property
def username(self):
return self._username
@username.deleter
def username(self):
print("Username deleted")
del self._username
استفاده:
user = User("Ali")
print(user.username)
del user.usernameخروجی:
Ali
Username deleted
🔹 سه بخش یک Property
حالا میتوانیم یک
property کامل داشته باشیم:class Product:
def __init__(self, price):
self._price = price
@property
def price(self):
return self._price
@price.setter
def price(self, value):
if value < 0:
raise ValueError("Price cannot be negative")
self._price = value
@price.deleter
def price(self):
del self._price
اینجا:
@property → خواندن
@price.setter → تغییر
@price.deleter → حذف
🔹 استفاده
product = Product(100)
print(product.price)
product.price = 200
print(product.price)
del product.price
در اینجا هر سه عملیات توسط
property کنترل میشوند.⚠️ نکته مهم
بعد از:
del product.price
دیگر
_price وجود ندارد.بنابراین اگر دوباره بنویسیم:
print(product.price)
با خطای
AttributeError مواجه میشویم.🧠 خلاصه
یک
property میتواند سه رفتار داشته باشد:@property
def value(self):
...
برای خواندن
@value.setter
def value(self, new_value):
...
برای تغییر
@value.deleter
def value(self):
...
برای حذف
🎯 تمرین
کلاس
Account را کامل کن تا ویژگی username قابلیت خواندن، تغییر و حذف داشته باشد:class Account:
def __init__(self, username):
self._username = username
@property
def username(self):
# کد اینجا
@username.setter
def username(self, value):
# کد اینجا
@username.deleter
def username(self):
# کد اینجا
سپس این کد را اجرا کن:
account = Account("Ali")
print(account.username)
account.username = "Reza"
print(account.username)
del account.usernameپست ۱۰۳ از دوره جامع Python 🐍
🐍 آموزش جامع Python — پست ۱۰۴
نمایش بهتر اشیاء با
حالا که با کلاسها و
به طور پیشفرض اگر یک شیء را چاپ کنیم، Python اطلاعاتی شبیه آدرس آن شیء نمایش میدهد.
برای کنترل این رفتار از دو متد ویژه استفاده میکنیم:
🔹
حالا:
خروجی:
🔹 اگر
مثلاً:
خروجی شبیه این خواهد بود:
این خروجی برای کاربر چندان مفید نیست.
با
🔹
حالا:
خروجی:
🔹 تفاوت
به ترتیب:
پس:
⚠️ نکته مهم
اگر
اما
🧠 خلاصه
برای:
و:
برای:
🎯 تمرین
کلاس زیر را کامل کن:
طوری بنویس که:
خروجی شبیه این باشد:
✅ پاسخ کامل تمرین
خروجی:
در
نمایش خوانا و مناسب برای کاربر ساخته میشود.
در
نمایش دقیقتری از نوع شیء و مقادیر آن ایجاد میکنیم.
پست ۱۰۴ از دوره جامع Python 🐍
نمایش بهتر اشیاء با
__str__ و __repr__حالا که با کلاسها و
@property آشنا شدیم، میخواهیم نحوه نمایش Objectها را کنترل کنیم.به طور پیشفرض اگر یک شیء را چاپ کنیم، Python اطلاعاتی شبیه آدرس آن شیء نمایش میدهد.
برای کنترل این رفتار از دو متد ویژه استفاده میکنیم:
__str__
__repr__
🔹
__str____str__ مشخص میکند وقتی شیء را با print() نمایش میدهیم، چه متنی نشان داده شود.class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __str__(self):
return f"{self.name} - {self.age} years old"
حالا:
person = Person("Ali", 25)
print(person)خروجی:
Ali - 25 years old
🔹 اگر
__str__ نداشته باشیممثلاً:
class Person:
def __init__(self, name):
self.name = name
person = Person("Ali")
print(person)
خروجی شبیه این خواهد بود:
<__main__.Person object at 0x...>
این خروجی برای کاربر چندان مفید نیست.
با
__str__ میتوانیم نمایش خواناتری داشته باشیم.🔹
__repr____repr__ برای ارائه یک نمایش دقیقتر و مناسب برای توسعهدهنده از شیء استفاده میشود.class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __str__(self):
return f"{self.name} ({self.age})"
def __repr__(self):
return f"Person(name={self.name!r}, age={self.age!r})"
حالا:
person = Person("Ali", 25)
print(person)
print(repr(person))خروجی:
Ali (25)
Person(name='Ali', age=25)
🔹 تفاوت
str() و repr()print(str(person))
print(repr(person))
به ترتیب:
Ali (25)
Person(name='Ali', age=25)
پس:
str → نمایش خواناتر برای کاربر
repr → نمایش دقیقتر برای توسعهدهنده
⚠️ نکته مهم
اگر
__str__ را تعریف نکرده باشیم، Python در بسیاری از موارد برای نمایش شیء میتواند از __repr__ استفاده کند.اما
__str__ و __repr__ هدف یکسانی ندارند:__str__ → نمایش دوستانه و قابلخواندن__repr__ → نمایش دقیقتر و مناسب توسعه و دیباگ🧠 خلاصه
def __str__(self):
return "..."
برای:
print(object)
و:
def __repr__(self):
return "..."
برای:
repr(object)
🎯 تمرین
کلاس زیر را کامل کن:
class Product:
def __init__(self, name, price):
self.name = name
self.price = price
def __str__(self):
# کد اینجا
def __repr__(self):
# کد اینجا
طوری بنویس که:
product = Product("Laptop", 1200)
print(product)
print(repr(product))خروجی شبیه این باشد:
Laptop - $1200
Product(name='Laptop', price=1200)
✅ پاسخ کامل تمرین
class Product:
def __init__(self, name, price):
self.name = name
self.price = price
def __str__(self):
return f"{self.name} - ${self.price}"
def __repr__(self):
return f"Product(name={self.name!r}, price={self.price!r})"
product = Product("Laptop", 1200)
print(product)
print(repr(product))
خروجی:
Laptop - $1200
Product(name='Laptop', price=1200)
در
__str__:return f"{self.name} - ${self.price}"نمایش خوانا و مناسب برای کاربر ساخته میشود.
در
__repr__:return f"Product(name={self.name!r}, price={self.price!r})"نمایش دقیقتری از نوع شیء و مقادیر آن ایجاد میکنیم.
پست ۱۰۴ از دوره جامع Python 🐍
1
🐍 آموزش جامع Python — پست ۱۰۵
تعیین طول شیء با
در پست قبل با
حالا یکی دیگر از متدهای جادویی (Magic Methods) را یاد میگیریم:
این متد مشخص میکند وقتی از
🔹 استفاده از
مثلاً میتوانیم برای یک کلاس
حالا:
خروجی:
🔹 چرا
Python نمیداند طول یک شیء ساختهشده از کلاس ما چقدر است.
با تعریف:
مشخص میکنیم
مثلاً:
خروجی:
⚠️ نکته مهم
مثلاً این اشتباه است:
چون
🔹 ارتباط با
یک نکته جالب:
اگر کلاس
خروجی:
چون طول شیء
اگر عضو داشته باشیم:
خروجی:
🎯 تمرین
کلاس
خروجی مورد انتظار:
پست ۱۰۵ از دوره جامع Python 🐍
تعیین طول شیء با
__len__در پست قبل با
__str__ و __repr__ آشنا شدیم.حالا یکی دیگر از متدهای جادویی (Magic Methods) را یاد میگیریم:
__len__
این متد مشخص میکند وقتی از
len() روی یک شیء استفاده میکنیم، چه مقداری برگردانده شود.🔹 استفاده از
__len__مثلاً میتوانیم برای یک کلاس
Playlist تعداد آهنگها را مشخص کنیم:class Playlist:
def __init__(self, songs):
self.songs = songs
def __len__(self):
return len(self.songs)
حالا:
playlist = Playlist(["Song 1", "Song 2", "Song 3"])
print(len(playlist))
خروجی:
3
🔹 چرا
__len__؟Python نمیداند طول یک شیء ساختهشده از کلاس ما چقدر است.
با تعریف:
def __len__(self):
مشخص میکنیم
len() چگونه مقدار طول را محاسبه کند.مثلاً:
class Team:
def __init__(self, members):
self.members = members
def __len__(self):
return len(self.members)
team = Team(["Ali", "Sara", "Reza", "Mina"])
print(len(team))
خروجی:
4
⚠️ نکته مهم
__len__ باید یک عدد صحیح (int) غیرمنفی برگرداند.مثلاً این اشتباه است:
def __len__(self):
return "5"
چون
"5" یک رشته است، نه عدد.🔹 ارتباط با
boolیک نکته جالب:
اگر کلاس
__bool__ نداشته باشد، Python میتواند از __len__ برای تعیین True یا False بودن شیء استفاده کند.class Team:
def __init__(self, members):
self.members = members
def __len__(self):
return len(self.members)
team = Team([])
print(bool(team))
خروجی:
False
چون طول شیء
0 است.اگر عضو داشته باشیم:
team = Team(["Ali"])
print(bool(team))
خروجی:
True
🎯 تمرین
کلاس
Cart را کامل کن تا len() تعداد محصولات سبد خرید را برگرداند:class Cart:
def __init__(self, products):
self.products = products
def __len__(self):
# کد اینجا
cart = Cart(["Laptop", "Mouse", "Keyboard"])
print(len(cart))
خروجی مورد انتظار:
3
پست ۱۰۵ از دوره جامع Python 🐍
1
🐍 آموزش جامع Python — پست ۱۰۶
مقایسه اشیاء با
تا اینجا دیدیم چطور رفتار شیء را با متدهایی مثل
حالا میخواهیم مشخص کنیم دو شیء چه زمانی برابر محسوب میشوند.
برای این کار از متد جادویی زیر استفاده میکنیم:
🔹
وقتی از
مثلاً:
حالا:
خروجی:
چون
🔹 اگر مقدارها متفاوت باشند
خروجی:
🔹 چرا این متد مهم است؟
بدون پیادهسازی
در این حالت نتیجه معمولاً:
است؛ چون
🔹 پارامتر
در این متد:
مثلاً:
تقریباً به این شکل بررسی میشود:
⚠️ نکته مهم
باید مراقب نوع
مثلاً این کد:
ممکن است باعث خطا شود، چون
یک روش امنتر:
🎯 تمرین
کلاس
خروجی مورد انتظار:
✅ پاسخ کامل تمرین
خروجی:
در این قسمت:
نام کاربری دو شیء را مقایسه میکنیم.
و در این قسمت:
سن دو شیء را مقایسه میکنیم.
در نهایت با
پست ۱۰۶ از دوره جامع Python 🐍
مقایسه اشیاء با
__eq__تا اینجا دیدیم چطور رفتار شیء را با متدهایی مثل
__str__ و __len__ کنترل کنیم.حالا میخواهیم مشخص کنیم دو شیء چه زمانی برابر محسوب میشوند.
برای این کار از متد جادویی زیر استفاده میکنیم:
__eq__
🔹
__eq__ چیست؟وقتی از
== استفاده میکنیم، Python میتواند از __eq__ برای مقایسه دو شیء استفاده کند.مثلاً:
class Product:
def __init__(self, name, price):
self.name = name
self.price = price
def __eq__(self, other):
return self.name == other.name and self.price == other.price
حالا:
product1 = Product("Laptop", 1200)
product2 = Product("Laptop", 1200)
print(product1 == product2)خروجی:
True
چون
name و price هر دو برابر هستند.🔹 اگر مقدارها متفاوت باشند
product1 = Product("Laptop", 1200)
product2 = Product("Laptop", 1500)
print(product1 == product2)خروجی:
False
🔹 چرا این متد مهم است؟
بدون پیادهسازی
__eq__، دو شیء مستقل معمولاً فقط به دلیل اینکه مقادیر مشابهی دارند، برابر در نظر گرفته نمیشوند.class Product:
def __init__(self, name, price):
self.name = name
self.price = price
product1 = Product("Laptop", 1200)
product2 = Product("Laptop", 1200)
print(product1 == product2)
در این حالت نتیجه معمولاً:
False
است؛ چون
product1 و product2 دو شیء جداگانه هستند.🔹 پارامتر
otherدر این متد:
def __eq__(self, other):
self به شیء سمت چپ و other به شیء سمت راست مقایسه اشاره میکند.مثلاً:
product1 == product2
تقریباً به این شکل بررسی میشود:
product1.__eq__(product2)
⚠️ نکته مهم
باید مراقب نوع
other باشیم.مثلاً این کد:
product == 100
ممکن است باعث خطا شود، چون
100 ویژگیهای name و price را ندارد.یک روش امنتر:
def __eq__(self, other):
if not isinstance(other, Product):
return NotImplemented
return self.name == other.name and self.price == other.price
NotImplemented به Python میگوید این مقایسه را با این نوع شیء نمیتوانیم انجام دهیم.🎯 تمرین
کلاس
User را طوری کامل کن که دو کاربر وقتی username و age یکسان دارند، برابر محسوب شوند:class User:
def __init__(self, username, age):
self.username = username
self.age = age
def __eq__(self, other):
# کد اینجا
user1 = User("ali", 25)
user2 = User("ali", 25)
user3 = User("sara", 25)
print(user1 == user2)
print(user1 == user3)
خروجی مورد انتظار:
True
False
✅ پاسخ کامل تمرین
class User:
def __init__(self, username, age):
self.username = username
self.age = age
def __eq__(self, other):
if not isinstance(other, User):
return NotImplemented
return (
self.username == other.username
and self.age == other.age
)
user1 = User("ali", 25)
user2 = User("ali", 25)
user3 = User("sara", 25)
print(user1 == user2)
print(user1 == user3)
خروجی:
True
False
در این قسمت:
self.username == other.username
نام کاربری دو شیء را مقایسه میکنیم.
و در این قسمت:
self.age == other.age
سن دو شیء را مقایسه میکنیم.
در نهایت با
and هر دو شرط باید True باشند تا دو کاربر برابر محسوب شوند.پست ۱۰۶ از دوره جامع Python 🐍
🐍 آموزش جامع Python — پست ۱۰۷
مقایسه اشیاء با
در پست قبل یاد گرفتیم با
حالا میخواهیم رفتار عملگر
برای این کار از:
استفاده میکنیم.
🔹
یعنی:
مثلاً میتوانیم محصولات را بر اساس قیمت مقایسه کنیم:
حالا:
خروجی:
چون:
🔹 مقایسه برعکس
خروجی:
چون:
صحیح نیست.
🔹
وقتی مینویسیم:
Python تقریباً این متد را فراخوانی میکند:
بنابراین:
به
به
⚠️ نکته مهم
یعنی با تعریف آن، لزوماً تمام عملگرهای مقایسهای دیگر (
هرکدام از این رفتارها متدهای ویژه مربوط به خودشان را دارند.
🔹 مثال کاربردی
میتوانیم دانشآموزها را بر اساس نمره مقایسه کنیم:
خروجی:
چون نمره
🎯 تمرین
کلاس
خروجی مورد انتظار:
پست ۱۰۷ از دوره جامع Python 🐍
مقایسه اشیاء با
__lt__در پست قبل یاد گرفتیم با
__eq__ مشخص کنیم دو شیء چه زمانی برابر هستند.حالا میخواهیم رفتار عملگر
< را برای اشیای کلاس خودمان تعریف کنیم.برای این کار از:
__lt__
استفاده میکنیم.
🔹
__lt__ چیست؟__lt__ مخفف Less Than است.یعنی:
<
مثلاً میتوانیم محصولات را بر اساس قیمت مقایسه کنیم:
class Product:
def __init__(self, name, price):
self.name = name
self.price = price
def __lt__(self, other):
return self.price < other.price
حالا:
product1 = Product("Mouse", 20)
product2 = Product("Keyboard", 50)
print(product1 < product2)خروجی:
True
چون:
20 < 50
🔹 مقایسه برعکس
print(product2 < product1)
خروجی:
False
چون:
50 < 20
صحیح نیست.
🔹
__lt__ چگونه اجرا میشود؟وقتی مینویسیم:
product1 < product2
Python تقریباً این متد را فراخوانی میکند:
product1.__lt__(product2)
بنابراین:
self
به
product1 و:other
به
product2 اشاره میکند.⚠️ نکته مهم
__lt__ فقط رفتار < را تعریف میکند.یعنی با تعریف آن، لزوماً تمام عملگرهای مقایسهای دیگر (
>, <=, >=) را برای کلاس تعریف نکردهایم.هرکدام از این رفتارها متدهای ویژه مربوط به خودشان را دارند.
🔹 مثال کاربردی
میتوانیم دانشآموزها را بر اساس نمره مقایسه کنیم:
class Student:
def __init__(self, name, score):
self.name = name
self.score = score
def __lt__(self, other):
return self.score < other.score
student1 = Student("Ali", 15)
student2 = Student("Sara", 18)
print(student1 < student2)
خروجی:
True
چون نمره
Ali کمتر از نمره Sara است.🎯 تمرین
کلاس
Book را کامل کن تا دو کتاب بر اساس قیمت با < مقایسه شوند:class Book:
def __init__(self, title, price):
self.title = title
self.price = price
def __lt__(self, other):
# کد اینجا
book1 = Book("Python", 30)
book2 = Book("Django", 45)
print(book1 < book2)
print(book2 < book1)
خروجی مورد انتظار:
True
False
پست ۱۰۷ از دوره جامع Python 🐍
🐍 آموزش جامع Python — پست ۱۰۸
مقایسه اشیاء با
در پست قبل با
حالا نوبت عملگر بزرگتر است:
برای تعریف این رفتار از متد جادویی:
استفاده میکنیم.
🔹
مثلاً میتوانیم محصولات را بر اساس قیمت مقایسه کنیم:
حالا:
خروجی:
چون:
🔹 مقایسه برعکس
خروجی:
چون:
صحیح نیست.
🔹
وقتی مینویسیم:
Python از متد مقایسهای مربوط به این عملگر استفاده میکند؛ در حالت معمول:
بنابراین:
به شیء سمت چپ و:
به شیء سمت راست اشاره میکند.
🔹 مثال با دانشآموز
خروجی:
چون نمره
⚠️ نکته مهم
را برای کلاس تعریف میکند.
برای عملگرهایی مانند:
متدهای مقایسهای دیگری وجود دارند.
در ادامه با آنها آشنا میشویم.
🎯 تمرین
کلاس
خروجی مورد انتظار:
پست ۱۰۸ از دوره جامع Python 🐍
مقایسه اشیاء با
__gt__در پست قبل با
__lt__ یاد گرفتیم رفتار عملگر < را برای اشیای کلاس خودمان تعریف کنیم.حالا نوبت عملگر بزرگتر است:
>
برای تعریف این رفتار از متد جادویی:
__gt__
استفاده میکنیم.
🔹
__gt__ چیست؟__gt__ مخفف Greater Than است.مثلاً میتوانیم محصولات را بر اساس قیمت مقایسه کنیم:
class Product:
def __init__(self, name, price):
self.name = name
self.price = price
def __gt__(self, other):
return self.price > other.price
حالا:
product1 = Product("Laptop", 1200)
product2 = Product("Mouse", 50)
print(product1 > product2)خروجی:
True
چون:
1200 > 50
🔹 مقایسه برعکس
print(product2 > product1)
خروجی:
False
چون:
50 > 1200
صحیح نیست.
🔹
__gt__ چگونه اجرا میشود؟وقتی مینویسیم:
product1 > product2
Python از متد مقایسهای مربوط به این عملگر استفاده میکند؛ در حالت معمول:
product1.__gt__(product2)
بنابراین:
self
به شیء سمت چپ و:
other
به شیء سمت راست اشاره میکند.
🔹 مثال با دانشآموز
class Student:
def __init__(self, name, score):
self.name = name
self.score = score
def __gt__(self, other):
return self.score > other.score
student1 = Student("Ali", 18)
student2 = Student("Sara", 15)
print(student1 > student2)
خروجی:
True
چون نمره
18 از 15 بیشتر است.⚠️ نکته مهم
__gt__ فقط رفتار عملگر:>
را برای کلاس تعریف میکند.
برای عملگرهایی مانند:
< <= >=
متدهای مقایسهای دیگری وجود دارند.
در ادامه با آنها آشنا میشویم.
🎯 تمرین
کلاس
Car را کامل کن تا خودروها بر اساس قیمت با > مقایسه شوند:class Car:
def __init__(self, model, price):
self.model = model
self.price = price
def __gt__(self, other):
# کد اینجا
car1 = Car("BMW", 50000)
car2 = Car("Toyota", 30000)
print(car1 > car2)
print(car2 > car1)
خروجی مورد انتظار:
True
False
پست ۱۰۸ از دوره جامع Python 🐍