ریاضی != پایتون، متود های جادویی!

همونطور که میدونید در ریاضی، جابجایی در ضرب و اضافه کردن تاثیری نداره.

2 + 5 = 5 + 2

ولی جالبه بدونید در زبان برنامه نویسی پایتون، اینطور نیست!



اگر تاحالا نگاهی به attribute های آبجکت های پایتون کرده باشید، اجزایی رو دیده اید که اسمشون با __ شروع و تموم میشه. شاید براتون سوال پیش اومده که این ها چی هستند و به چه درد میخورند!؟

در این مقاله بعضی از اون هارو توضیح میدیم

>>> dir(5)
['__abs__', '__add__', '__and__', '__bool__', '__ceil__', '__class__', '__delattr__', '__dir__', '__divmod__', '__doc__', '__eq__', '__float__', '__floor__', '__floordiv__', '__format__', '__ge__', '__getattribute__', '__getnewargs__', '__gt__', '__hash__', '__index__', '__init__', '__init_subclass__', '__int__', '__invert__', '__le__', '__lshift__', '__lt__', '__mod__', '__mul__', '__ne__', '__neg__', '__new__', '__or__', '__pos__', '__pow__', '__radd__', '__rand__', '__rdivmod__', '__reduce__', '__reduce_ex__', '__repr__', '__rfloordiv__', '__rlshift__', '__rmod__', '__rmul__', '__ror__', '__round__', '__rpow__', '__rrshift__', '__rshift__', '__rsub__', '__rtruediv__', '__rxor__', '__setattr__', '__sizeof__', '__str__', '__sub__', '__subclasshook__', '__truediv__', '__trunc__', '__xor__', 'as_integer_ratio', 'bit_length', 'conjugate', 'denominator', 'from_bytes', 'imag', 'numerator', 'real', 'to_bytes']



در پایتون وقتی دو عدد با هم جمع داده میشه، کاربر فقط عددها و علامت + رو وارد میکنه و نتیجه رو دریافت میکنه، اما در پشت صحنه برای پردازش این عمل جمع، متود __add__ اجرا میشه.

برای مثال وقتی عدد 3 رو با 5 جمع میکنید (3 + 5)، در حقیقت این عمل انجام میگیره:

>>> (3).__add__(5)
8

پس طبیعیه که اگر برعکسش رو انجام بدیم (5 + 3)، عمل متفاوتی انجام میشه:

>>> (5).__add__(3)
8

ولی نتیجه یکسانه، چون دو آبجکتی که ما جمع میکنیم یه نوع دارن و شرط های یکسانی هم برای جمع کردن دارن.

حالا بیاید دو تا آبجکت بسازیم که جمع اولی با دومی ممکن، و برعکسش یعنی جمع دومی با اولی غیر ممکن باشه.

class ObjectA:
    def __add__(self, obj):
        return f'Added ObjectA to {obj}'

class ObjectB:
    def __add__(self, obj):
        if type(obj) != ObjectA:
            return f'Added ObjectB to {obj}'
        else:
            raise Exception('You can\'t add a ObjectB to a ObjectA!')        

همونطور که میبینید ObjectA قابلیت اینو داره که با هر آبجکتی جمع بسته بشه ولی ObjectB با ObjectA نمیتونه اینکار رو بکنه.

پس دیدید که جابجایی در + میتونه تغییر ایجاد کنه!

به اینجور متود ها که به جز call کردن با روش های دیگه ای هم فراخوانی میشن اصطلاحا میگن magic methods یا متود های جادویی.

ضرب و تقسیم و خیلی از قابلیتای دیگه هم با این متودا عمل میکنن.

چند مثال از متود های جادویی:

  • __add__ | جمع (+)
  • __reduce__ | تفریق (-)
  • __mul__ | ضرب (*)
  • __repr__ | استفاده برای متود repr
  • __divmod__ | استفاده برای متود divmod

و بسیار متود های دیگه که میتونید اونارو از این سایت و سایت های دیگر موجود در گوگل دریافت کنید.



برای مثالی دیگر متود __str__ رو توضیح میدم.

در حالت عادی وقتی کلاستون رو پرینت میکنید یا جایی نمایشش میدید، چیزی مثل عکس زیر دریافت میکنید:

<__main__.Tutorial object at 0x7fb1037678b0>

ولی با متود __str__ میتونید اونو تغییر بدید!



این متود ها برای شی گرایی و ساختن کتاب خونه و فریم ورک خیلی کاربردی هستن و میتونن در user-friendly ساختن محصولتون خیلی کمک کنن.