اصطلاح “چند شکلی” یا “چند ریختی” یا polymorphism از زبان یونانی گرفته شده و به معنای چیزی است که چندین شکل به خود می گیرد.چند ریختی به توانایی یک زیر کلاس برای انطباق متدی که قبلاً در سوپرکلاس آن وجود دارد برای رفع نیازهایش اشاره دارد. به بیان دیگر، یک زیر کلاس می تواند از متدی از سوپرکلاس خود استفاده کند یا در صورت نیاز آن را تغییر دهد.همان کلاس Person که در مطالب قبلی استفاده کردیم را در نظر بگیرید:

class Person:
    def __init__(self, first_name, last_name, IDnumber ):
        self.firstname=first_name
        self.lastname=last_name
        self.ID=IDnumber
        self.salary = None
    def set_salary(self, salary):
        self.salary = salary

با استفاده از این کلاس می توان اعضای شاغل در یک شرکت را تعریف نمود و نام و نام خانوادگی و شماره پرسنلی آنها را مشخص کرد. همچنین از طریق متد set_salary می توان در زمان لزوم حقوق هر شخص را نیز معین کرد.

حالا فرض کنیم که بعضی کارمندها رتبه بالاتری دارند و حقوق آنها 10 درصد بیشتر از سایر کارمندان است و قصد داریم یک کلاس فرزند برای آنها ایجاد کنیم و بتوانیم حقوق آنها را جداگانه مشخص کنیم.

برای ایجاد یک زیر کلاس که از چند شکلی استفاده می کند، می توانیم یک کلاس جدید تعریف کنیم که از کلاس Person به ارث می برد و متد set_salary را دوباره در آن تعریف نماییم. Polymorphism به ما این امکان را می دهد که از یک متد با نام مشابه در کلاس های مختلف، اما با پیاده سازی های متفاوت استفاده کنیم.

class Senior(Person):
    def set_salary(self, salary):
        self.salary = salary * 1.1

کلاس Senior از کلاس Person ارث می برد و متد set_salary یک بار هم در این کلاس تعریف شده است. متد set_salary در کلاس Employee حقوق را در 1.1 ضرب می کند که حقوق را 10% افزایش می دهد. برای ایجاد یک کارمند ارشد با استفاده از این کلاس به این صورت عمل می کنیم:

nahid = Senior("Nahid", "Karami", '5824687')
nahid.set_salary(70000000)
print(nahid.salary)

با اجرای این کد خواهیم دید که حقوق این کارمند 77000000 ریال تعیین می شود.

اما اگر یک کارمند را با همان کلاس Person ایجاد کنیم حقوقش 70000000 خواهد بود:

kamran=Person('Kamran' , 'Hamidi' , '1257148')
kamran.set_salary(70000000)
print(kamran.salary)

نادیده گرفتن متد یا overriding

وقتی متدی با همان نام و آرگومان‌ها هم در یک کلاس فرزند و هم در کلاس پایه یا والد استفاده می‌شود، می‌گوییم که متد کلاس فرزند، متد ارائه‌شده در کلاس والد را لغو می‌کند یا نادیده می گیرد.

وقتی این متد فراخوانی می شود، همیشه متد کلاس فرزند فراخوانی می شود و متدی که در کلاس والد استفاده شده اکنون پنهان می شود.

متد set_salary در مثال ما از همین قاعده پیروی می کند.

استفاده از تابع super

برای تعریف کلاس Senior و بازنویسی متد set_salary به طریق دیگری نیز می توانیم عمل کنیم.

class Senior(Person):
   def set_salary(self, salary):
       super().set_salary(salary * 1.1)

در پایتون، وقتی یک زیر کلاس ایجاد می کنید، می توانید از تابع super برای فراخوانی متدی از سوپرکلاس استفاده کنید. تابع super یک شی موقت از superclass یا کلاس والد را برمی گرداند که امکان دسترسی به تمام متدهای آن را از زیر کلاس فراهم می کند.

این زمانی مفید است که می‌خواهید متدی را در سوپرکلاس بازنویسی کنید، اما همچنان می‌خواهید از متد اصلی هم در کلاس فرعی استفاده نمایید. با استفاده از super، می توانید از تکرار کد جلوگیری و کد خود را قابل نگهداری تر کنید.

اجرای کد زیر دقیقا نتیجه ای مانند قبل خواهد داشت:

nahid = Senior("Nahid", "Karami", '5824687')
nahid.set_salary(70000000)
print(nahid.salary)

ما می توانیم از super در متد __init__ یک زیر کلاس برای فراخوانی متد __init__ سوپرکلاس نیز استفاده کنیم. در اینجا کلاس Senior را با استفاده از super در متد __init__ بازنویسی می کنیم:

class Senior(Person):
    def __init__(self, first_name, last_name, IDnumber, salary):
        super().__init__(first_name, last_name, IDnumber)
        self.salary = salary

در این مثال، کلاس Senior از کلاس Person ارث می برد. متد __init__ در کلاس Senior از super برای فراخوانی متد __init__ از کلاس Person استفاده می کند و پارامترهای مورد نیاز را از آن دریافت می کند. اما متد __init__ در کلاس Senior ویژگی salary را مقداردهی اولیه می کند.

بنابراین برای معرفی یک کارمند با کلاس Senior به این شکل عمل می کنیم:

nahid = Senior("Nahid", "Karami", '5824687',77000000)
print(nahid.salary)

این بار حقوق را مستقیما موقع تعریف شی جدید وارد کرده ایم. همچنین برای تغییر حقوق می توانیم از متد set_salary از کلاس والد استفاده نماییم.

nahid.set_salary(80000000)