مسیر شما: سبز دانش » برنامه نویسی » پایتون » متدهای جادویی در پایتون: تعریف و لیست کاربرد Dunder Methodها
وقتی با کلاسهای پایتون کار میکنیم، احتمالاً متدهایی با دو علامت _ در ابتدا و انتهای نامشان (مثل __init__ و __str__) مواجه میشویم. در نگاه اول این متدها کمی عجیب و غریب به نظر میرسند، اما آنها بخش مهمی از نحوه کار اشیاء در پایتون هستند.
متدهای جادویی یا Dunder Methodها، متدهای خاصی در پایتون هستند که رفتار شیء (Object) را هنگام انجام بعضی عملیاتها مشخص میکنند. نکته جالب این است که خیلی وقتها خودمان مستقیماً آنها را صدا نمیزنیم؛ بلکه مفسر پایتون متد مناسب را در پشت صحنه فراخوانی و استفاده میکند.
مثلاً وقتی روی یک لیست تابع len() را صدا میزنیم، پایتون برای محاسبه طول لیست، متد __len__() را از کلاس list فراخوانی میکند. یعنی وقتی مینویسیم:
numbers = [10, 20, 30]
print(len(numbers))میتوانیم تصور کنیم که پایتون رفتاری شبیه به زیر را برای len(numbers) دارد:
numbers.__len__()یا وقتی برای دسترسی به یکی از اعضای لیست در پایتون مینویسیم:
numbers[2]متد __getitem__(2) عضو مورد نظر را از لیست پیدا کرده و به ما میدهد.
در این آموزش پس از تعریف متدهای جادویی، چند متد پرکاربرد را با مثال تحلیل میکنیم. در نهایت نیز یک لیست جمعوجور از مهمترین متدها و کاربردهایشان را برایتان قرار میدهم.
فهرست محتوای آموزش
متدهای جادویی متدهای یک کلاس هستند؛ با این تفاوت که نام خاصی دارند و مفسر پایتون در موقعیتهای مختلف آنها را فراخوانی میکند.
مثلاً میتوانیم تعیین کنیم که وقتی شیء ما با تابع print() چاپ شد، چه چیزی نمایش داده شود؛ یا وقتی که همان شیء با عملگر + استفاده شد، چه رفتاری داشته باشد.
در مستندات رسمی (+)، معمولاً به این متدها Special Method (متد خاص) گفته میشود. اما ممکن است آنها را با نامهای Magic Method (متد جادویی) یا Dunder Method نیز بشنوید. همگی صحیح هستند.
کلمه Dunder کوتاه شدهی Double Underscore است؛ یعنی دو تا زیرخط یا همان علامت _. تمام متدهای جادویی در ابتدا و انتهای اسمشان دو تا underscore دارند.
__init__
__str__
__len__
به همین دلیل به آنها Dunder Method نیز میگوییم.
برای درک بهتر، فرض کنید یک کلاس برای محصولات فروشرسانیگاه اینترنتی داریم. اگر میخواهید با مفهوم کلاس، شیء و متد بهطور دقیق آشنا شوید و کار کنید، پیشنهاد میکنم جلسه آموزش کلاس در پایتون از دوره آموزش پایتون را ببینید.
کلاس Product را بهصورت زیر تعریف میکنیم:
class Product:
def __init__(self, name):
self.name = name
def __str__(self):
return "Product name: " + self.nameدر بدنهٔ متد __str__ که یک متد جادویی است، تعریف کردهام که وقتی خواستیم شیء را چاپ کنیم، علاوه بر اسم محصول، عبارت Product name: نیز قبل از آن قرار بگیرد.
بنابراین اگر یک شیء با name = "Laptop" ایجاد کنیم و بخواهیم آن را پرینت کنیم، علاوه بر اسم Laptop، عبارت Product name: نیز قبل و همراه با آن چاپ میشود. یعنی چیزی شبیه به قطعه کد زیر:
product = Product("Laptop")
print(product) # Product name: Laptopدر این مثال، دستور print(product) باعث میشود که پایتون به شکل نمایش متنی شیء نیاز داشته باشد. بنابراین متد جادویی __str__ را صدا میزد تا شکل متنی آن را دریافت کند. ما در متد __str__ علاوهبر اینکه self.name را برگرداندهایم، یک عبارت دلخواه نیز به آن متصل کردهایم. به همین دلیل خروجی نهایی اینچنین میشود.
در این بخش چند مورد از Dunder methodهایی که خیلی بیشتر در پروژههای شیءگرایی پایتون دیده و استفاده میشود را معرفی و با یک مثال کوتاه مرور میکنیم.
این همان متدی است که در آموزش تعریف کلاس در پایتون با آن آشنا شدیم و کار کردیم. اصطلاحاً به آن متد سازنده (Constructor) نیز میگوییم.
وقتی قرار است یک شیء از کلاسی ساخته شود، این متد در آن کلاس فراخوانی میشود و معمولاً از آن برای مقداردهی اولیه استفاده میشود.
class User:
def __init__(self, name):
self.name = name
test_user = User("Omid")
print(test_user.name) # Omidدر مثال بالا، هنگام اجرای User("Omid") مقدار "Omid" بهعنوان آرگومان ورودی به __init__() داده میشود و قابلیت name مقداردهی خواهد شد.
اگر بخواهیم مشخص کنیم که شیء هنگام print() شدن یا تبدیل به رشته (مثلاً با تابع str()) چگونه نمایش شود، از این متد جادویی پایتون استفاده میکنیم. دقیقاً مشابه مثالی که در بخش قبلی زدم.
این متد جادویی برای تعیین نمایش رشتهای و متنی شیء استفاده میشود اما معمولاً هدف آن ارائه یک نمایش دقیقتر و مناسب برای رفع خطا و debug کردن کد است. در ادامه از آن برای مرور شیء در هنگام کدنویسی کمک میگیریم.
نحوه تعریف و استفاده از آن با تابع repr() را در قطعه کد زیر میبینید:
class Product:
def __repr(self):
return "This is a test for object's details"
test = Product()
print( repr(test) )وقتی از عملگر مقایسهای == بین دو شیء استفاده میکنیم، پایتون رفتار تعریفشده توسط __eq__() را برای مقایسه استفاده میکند.
مثلاً در کلاس Product برای هر محصول یک شناسه (بارکد/id) تعریف کردهایم. میخواهیم مشخص کنیم که اگر قرار بود دو شیء از این کلاس با عملگر == با یکدیگر مقایسه شوند، idهای آنها با یکدیگر مقایسه شوند. برای این کار قطعه کد زیر را خواهیم داشت:
class Product:
def __init__(self, id):
self.id = id
def __eq__(self, other):
return self.id == other.id
p1 = Product("101")
p2 = Product("101")
print( p1 == p2 ) # Trueتوجه کنید که نوع id یک رشته است. من در متد __eq__ تعریف کردهام که مقدار دو تا رشته با هم مقایسه شود. بنابراین مجدداً متد جادویی __eq__() در کلاس String فراخوانی میشود. البته کلاس رشته در پایتون یک کلاس از پیشتعریفشده (Built-in) است و نیازی به تعریف آن نداشتیم.
با این متد جادویی میتوانیم مشخص کنیم وقتی که دو شیء از کلاسمان با + جمع شدند، چه اتفاقی بیفتد.
در قطعه کد زیر، برای کلاس Product عملیات + را معادل با جمع نرخ دو محصول تعریف میکنیم:
class Product:
def __init__(self, id, price):
self.id = id
self.price = price
def __add__(self, other):
return self.price + other.price
p1 = Product("101", 250000)
p2 = Product("102", 310000)
total_price = p1 + p2
print(total_price) # 560000واضح است که اسم other بهعنوان آرگومان، یک اسم دلخواه است؛ بنابراین میتوانید هر اسم دیگری نیز باشد.
یادتان باشد که در بدنهٔ متدهای جادویی پایتون، میتوانیم هر کاری انجام دهیم؛ از محاسبه و خروجی گرفته تا نمایش یک پیغام. حتی میتوانیم یک خطا به کاربر بدهیم. اگر با چگونگی آن آشنا نیستید، آموزش ایجاد خطا با raise در پایتون را ببینید.
گاهی میخواهیم مشخص کنیم که اگر شیء ما در یک ساختار شرطی پایتون (if) قرار گرفت، چه زمانی True بدهد و چه زمانی False. این کار را میتوانیم با متد __bool__() کنترل کنیم.
فرض کنید در کلاس Product مشخصهای به نام stock_quantity داریم که تعداد موجودی محصول برای عرضه را در خود ذخیره میکند. میخواهم طوری تعریف کنم که اگر شیء محصول در ساختار شرطی قرار گرفت، اگر موجودی بیشتر از صفر بود True و در غیراینصورت False برگرداند.
برای چنین منطقی، قطعه کد زیر را خواهیم داشت:
class Product:
def __init__(self, id, price, init_quantity):
self.id = id
self.price = price
self.stock_quantity = init_quantity
def __bool__(self):
return self.stock_quantity > 0تعداد متدهای جادویی در پایتون زیاد است و هر کدام رفتار خاصی در مدل دادهای پایتون دارند. در این بخش در چند جدول و دستهبندی مختصر، چند نمونه از آنها را با هم مرور میکنیم.
نیازی نیست که تمام متدهای جادویی را حفظ کنید! همین که بدانید چنین مفهومی وجود دارد و قابل تعریف است کافی است. بعداً با یک جستجو در مستندات یا پرسوجو از دستیارهای هوش مصنوعی به متدهای مدنظرمان میرسیم.
متد __new__() زمانی اهمیت پیدا میکند که بخواهیم خودِ فرآیند ایجاد شیء را کنترل کنیم؛ در حالیکه __init__() اکثراً برای آمادهسازی شیء بلافاصله پس از ایجاد استفاده میشود.
در این آموزش دیدیم که متد جادویی یا Magic Method یا Special Method برای تعیین رفتار شیء در عملیاتهای خاص استفاده میشود. ممکن است بهطور مستقیم آنها را صدا نزنیم و مفسر پایتون خودش تصمیم بگیرد کدام را در چه زمانی فراخوانی کند.
مثلاً وقتی مینویسیم:
print( obj )متد جادویی __str__() برای تبدیل شیء به رشته صدا زده میشود.
یا وقتی که مینویسیم:
len( obj )منطقِ درون متد __len__() برای محاسبه اندازه شیء استفاده میشود.
مجدد متذکر میشوم که نیاز نیست لیست متدهای جادویی پایتون را حفظ کنید. مهمتر این است که بدانید چنین مفهومی وجود دارد و بهطور حدودی کدام رفتارها توسط Dunder/Magic Methodها کنترل و مدیریت میشوند.
بهطور خلاصه، متدهای جادویی، متدهای خاصی در پایتون هستند که ابتدا و انتهای اسم آنها دو تا علامت _ وجود دارد. این متدها رفتارهای شیء ما را در عملیاتهای مختلف مثل ایجاد، مقداردهی اولیه، تبدیل به رشته، محاسبه اندازه و نحوه محاسبه عملگرهای مختلف روی آنها را تعیین میکند.
امیدوارم از این آموزش نهایت استفاده را برده باشید. اگر سؤال یا چالشی دارید، از بخش دیدگاهها مطرح کنید.
این آموزش برای همیشه بدون هزینهه! میتونید با اشتراکگذاری لینک این صفحه از ما حمایت کنید یا با خریداری یه فنجون نوشیدنی بهمون انرژی بدید!
برچسب:
نویسنده: استخدام کار