Magic Methods و Operator Overloading

  • مدرس: علی بیگدلی
  • تاریخ انتشار: 1402/05/03
  • تعداد بازدید: 140

روش های جادویی روش های ویژه ای هستند که در ابتدا و انتهای اسامی آنها دارای تائید دوگانه هستند. آنها همچنین به عنوان دونده (dunders) شناخته می شوند. تا کنون، تنها چیزی که ما با آن مواجهیم __init__ است، اما چندین مدل دیگر نیز وجود دارند. از آنها برای ایجاد قابلیت هایی که نمی توانند به عنوان یک روش معمول نمایش داده شوند استفاده می شوند. یکی از کاربردهای رایج از آنها، بارگذاری اپراتور است. این به معنی تعریف اپراتورها برای کلاسهای سفارشی است که اجازه می دهد اپراتورهایی مانند + و * در آنها استفاده شوند. یک متد جادویی (magic method) ، متد __add__ برای + است.

class Vector2D:
  def __init__(self, x, y):
    self.x = x
    self.y = y
  def __add__(self, other):
    return Vector2D(self.x + other.x, self.y + other.y)

first = Vector2D(5, 7)
second = Vector2D(3, 9)
result = first + second
print(result.x)
print(result.y)

خروجی:

>>>
8
16    
>>>

نکته:روش __add__ برای تعریف یک رفتار سفارشی برای اپراتور + در کلاس ما اجازه می دهد. همانطور که می بینید، ویژگی های متناظر مربوط به اشیاء را اضافه می کند و یک شی جدید را با نتیجه می گیرد. هنگامی که تعریف می شود، می توانیم دو اشیاء کلاس را با هم اضافه کنیم. روش های جادویی بیشتر برای اپراتورهای مشترک: __sub__ برای - __mul__ برای * __truediv__ برای / __floordiv__ برای __mod__ برای٪ __pow__ برای ** __و برای & __xor__ برای ^ __or__ برای | بیان x + y به x .__ اضافه می شود __ (y). با این حال، اگر x __add__ اجرا نکند، و x و y از انواع مختلف هستند، سپس y_____radd __ (x) نامیده می شود. روش های معادل R برای تمام روش های جادویی که فقط ذکر شده اند وجود دارد. مثال:

class SpecialString:
  def __init__(self, cont):
    self.cont = cont

  def __truediv__(self, other):
    line = "=" * len(other.cont)
    return "\n".join([self.cont, line, other.cont])

spam = SpecialString("spam")
hello = SpecialString("Hello world!")
print(spam / hello)

پایتون همچنین روشهای جادویی برای مقایسه را فراهم می کند. __lt__ برای < __le__ برای <= __ eq__ برای == __ne__ برای! = __gt__ برای> __ge__ برای> = اگر __ne__ اجرا نگردد، مخالف __eq__ باز می گردد. هیچ ارتباطی بین اپراتورهای دیگر وجود ندارد. مثال:

class SpecialString:
  def __init__(self, cont):
    self.cont = cont

  def __gt__(self, other):
    for index in range(len(other.cont)+1):
      result = other.cont[:index] + ">" + self.cont
      result += ">" + other.cont[index:]
      print(result)

spam = SpecialString("spam")
eggs = SpecialString("eggs")
spam > eggs

خروجی:

>>>
>spam>eggs
e>spam>ggs
eg>spam>gs
egg>spam>s
eggs>spam>
>>>

نکته:همانطور که می بینید، می توانید هر گونه رفتار سفارشی برای اپراتورهای بیش از حد تعریف کنید. چند روش جادویی برای ایجاد طبقات مانند ظروف وجود دارد. __len__ برای len () __getitem__ برای نمایه سازی __setitem__ برای اختصاص به مقادیر شاخص شده __delitem__ برای حذف شاخص های نشان داده شده __iter__ برای تکرار بیش از اشیاء (به عنوان مثال، در حلقه ها) __Contains__ برای بسیاری از روش های جادویی دیگر وجود دارد که ما در اینجا نمی توانیم پوشش دهیم، مانند __call__ برای فراخوانی اشیاء به عنوان توابع و __int__، __str__ و مانند آن، برای تبدیل اشیا به انواع ساخته شده. مثال:

import random

class VagueList:
  def __init__(self, cont):
    self.cont = cont

  def __getitem__(self, index):
    return self.cont[index + random.randint(-1, 1)]

  def __len__(self):
    return random.randint(0, len(self.cont)*2)

vague_list = VagueList(["A", "B", "C", "D", "E"])
print(len(vague_list))
print(len(vague_list))
print(vague_list[2])
print(vague_list[2])

خروجی:

>>>
6
7
D
C
>>>

نکته:ما تابع len () را برای VagueList کلاس برای بازگشت یک عدد تصادفی برداشته ایم. تابع نمایه سازی نیز یک عنصر تصادفی را در یک محدوده از لیست بر اساس عبارت نمایش می دهد.