برنامه نویسی شی گرا در پایتون | به زبان ساده
در این مطلب، مفاهیم پایهای «برنامهنویسی شیگرا» (Object Oriented Programming) از جمله مفهوم کلاس در برنامه نویسی و همچنین، چگونگی انجام برنامه نویسی شی گرا در پایتون همراه با مثالهای متعدد آموزش داده شده است.
برنامه نویسی شی گرا در پایتون
«زبان برنامهنویسی پایتون» (Python Programming Language)، یک زبان برنامهنویسی چند پارادایمی است. بدین معنا که از رویکردهای برنامهنویسی گوناگونی پشتیبانی میکند. یک راهکار محبوب برای حل مسائل برنامهنویسی، ساخت «شی» (Object) است.
زبانهای برنامهنویسی که از این رویکرد و در واقع پارادایم برنامهنویسی پشتیبانی میکنند را «شیگرا» (Object Oriented) و برنامهنویسی با این پارادایم را «برنامهنویسی شیگرا» (Object Oriented Programming) میگویند. یک شی، دو مشخصه دارد:
- خصیصه
- رفتار
مثالی که در ادامه میآید، در این راستا قابل توجه است. در اینجا، «طوطی» (Parrot) یک شی است.
- نام (Name)، سن (Age) و رنگ (Color) مشخصههای شی طوطی آن هستند.
- خواندن (Singing) و حرکات موزون (Dancing) رفتار شی طوطی محسوب میشوند.
مفهوم OOP در پایتون، بر ساخت کدهای قابل استفاده مجدد تمرکز دارد. این مفهوم با عنوان «DRY» (سرنامی برای عبارت Don't Repeat Yourself) نیز شناخته شده است و بدان معنا است که کاری که یکبار انجام شده را نباید مجدد تکرار کرد و در واقع، میتوان از کدها استفاده مجدد کرد. استفاده مجدد از کدهای نوشته شده، یکی از مباحث مهم در بحث مهندسی نرمافزار است. در پایتون، مفهوم OOP از چند اصل پایهای پیروی میکند که در ادامه شرح داده شدهاند.
- ارثبری (Inheritance): فرایند استفاده از جزئیات از کلاس جدید بدون ویرایش کلاس موجود را ارثبری گویند.
- کپسولهسازی (Encapsulation): پنهانسازی جزئیات خصوصی یک کلاس از اشیای دیگر را کپسولهسازی گویند.
- چندریختی (Polymorphism): مفهوم استفاده از عملیات متداول به روشهای متفاوت برای ورودیهای داده متفاوت را چندریختی یا پلیمورفیسم گویند.
کلاس
یک کلاس، یک «نقشه ساخت» (بلوپرینت | BluePrint) برای یک شی است. میتوان به یک کلاس به عنوان پیشطرح (اسکیس | Sketch) از طوطی (Parrot) با برچسبهای آن نگاه کرد. کلاس همه جزئیات درباره نام، رنگها، اندازه و دیگر موارد را دارد.
بر اساس این توضیحات، میتوان درباره طوطی مطالعه کرد. در اینجا، طوطی یک شی است. مثال کلاس طوطی (Parrot) به صورت زیر است:
1class Parrot:
2 pass
در اینجا، از کلیدواژه class برای تعریف یک کلاس خالی Parrot استفاده شده است. از کلاسها، میتوان نمونههایی (Samples) نیز ساخت. یک نمونه، یک شی خاص است که از یک کلاس مشخص ساخته شده است.
شی
یک شی (نمونه)، یک نمونه از یک کلاس است. هنگامی که کلاس تعریف میشود، تنها توصیف شی تعریف میشود. بنابراین، هیچ حافظه یا فضای ذخیرهسازی به آن تخصیص داده نمیشود.
مثال، برای شی کلاس parrot، به صورت زیر است:
1obj = Parrot()
در اینجا، obj شی کلاس Parrot است. فرض میشود که برنامهنویس جزئیاتی را پیرامون parrot دارد. اکنون، هدف آن است که نشان داده شود چگونه کلاس و شیهای parrot ساخته میشوند.
مثال ۱: ساخت کلاس و شی در پایتون
1class Parrot:
2
3 # class attribute
4 species = "bird"
5
6 # instance attribute
7 def __init__(self, name, age):
8 self.name = name
9 self.age = age
10
11# instantiate the Parrot class
12blu = Parrot("Blu", 10)
13woo = Parrot("Woo", 15)
14
15# access the class attributes
16print("Blu is a {}".format(blu.__class__.species))
17print("Woo is also a {}".format(woo.__class__.species))
18
19# access the instance attributes
20print("{} is {} years old".format( blu.name, blu.age))
21print("{} is {} years old".format( woo.name, woo.age))
پس از اجرای برنامه بالا، خروجی به صورت زیر خواهد بود.
1Blu is a bird
2Woo is also a bird
3Blu is 10 years old
4Woo is 15 years old
در برنامه بالا، یک کلاس با نام Parrot ساخته میشود. سپس، خصیصهها تعریف میشوند. خصیصهها مشخصات یک شی هستند. سپس، نمونههای کلاس Parrot ساخته میشوند. در اینجا، blu و woo مراجعی (مقادیر) برای اشیای جدید هستند. سپس، با استفاده از class __.species__ به کلاس مشخصه میتوان دسترسی داشت. خصیصههای کلاس برای همه نمونههای یک کلاس مشابه هستند. به طور مشابه، میتوان به خصیصههای نمونهها با استفاده از blu.name و blu.age دسترسی داشت. اگرچه، خصیصههای نمونه برای هر نمونه از کلاس متفاوت هستند.
متدها
متدها (Methods) توابعی هستند که درون بدنه یک کلاس تعریف میشوند. از این متدها برای تعریف رفتار یک شی استفاده میشود.
مثال ۲: ساخت متدها در پایتون
1class Parrot:
2
3 # instance attributes
4 def __init__(self, name, age):
5 self.name = name
6 self.age = age
7
8 # instance method
9 def sing(self, song):
10 return "{} sings {}".format(self.name, song)
11
12 def dance(self):
13 return "{} is now dancing".format(self.name)
14
15# instantiate the object
16blu = Parrot("Blu", 10)
17
18# call our instance methods
19print(blu.sing("'Happy'"))
20print(blu.dance())
هنگامی که برنامه اجرا میشود، خروجی به صورت زیر خواهد بود:
Blu sings 'Happy' Blu is now dancing
در برنامه بالا، دو متد ()sing و ()dance تعریف شدهاند. به این دو، متد نمونه (Instance Method) گفته میشود، زیرا روی یک شی نمونه فراخوانی میشوند، در مثال بالا، blu یک متد نمونه است.
ارثبری
ارثبری (Inheritance) راهکاری برای ساخت یک کلاس جدید برای استفاده از جزئیات موجود در یک کلاس بدون ویرایش آن است. کلاس جدیدی که شکل میگیرد، یک کلاس مشتق شده (یا کلاس فرزند) است. به طور مشابه، کلاس موجود، کلاس مبنا (کلاس والد) است.
مثال ۳: استفاده از ارثبری در پایتون
1# parent class
2class Bird:
3
4 def __init__(self):
5 print("Bird is ready")
6
7 def whoisThis(self):
8 print("Bird")
9
10 def swim(self):
11 print("Swim faster")
12
13# child class
14class Penguin(Bird):
15
16 def __init__(self):
17 # call super() function
18 super().__init__()
19 print("Penguin is ready")
20
21 def whoisThis(self):
22 print("Penguin")
23
24 def run(self):
25 print("Run faster")
26
27peggy = Penguin()
28peggy.whoisThis()
29peggy.swim()
30peggy.run()
خروجی حاصل از اجرای برنامه بالا، به صورت زیر است.
Bird is ready Penguin is ready Penguin Swim faster Run faster
در برنامه بالا، دو کلاس، برای مثال Bird (کلاس والد) و Penguin (کلاس فرزند) ساخته شده است. کلاس فرزند از توابع کلاس والد ارثبری میکند. میتوان این مورد را از متد ()swim دید. دوباره، کلاس فرزند، رفتار کلاس والد را ویرایش میکند. میتوان این مورد را از متد ()whoisThis دید. علاوه بر آن، توابع کلاس فرزند با ساخت یک متد ()run جدید، توسعه پیدا میکنند. همچنین، از تابع ()super پیش از متد ()__init__ استفاده میشود. این بدین دلیل است که هدف، کشیدن (pull) محتوای متد ()__init__ از کلاس والد به کلاس فرزند است.
کپسولهسازی
با استفاده از OOP، میتوان دسترسی به متدها و متغیرها را محدود کرد. این کار از ویرایش مستقیم دادهها جلوگیری میکند و کپسولهسازی نام دارد.
در پایتون، خصیصههای خصوصی (Private Attribute) با استفاده از یک (ـ) یا دو علامت زیر خط (ــ) به صورت پیشوند، تعریف میشوند.
مثال ۴: کپسولهسازی دادهها در پایتون
1class Computer:
2
3 def __init__(self):
4 self.__maxprice = 900
5
6 def sell(self):
7 print("Selling Price: {}".format(self.__maxprice))
8
9 def setMaxPrice(self, price):
10 self.__maxprice = price
11
12c = Computer()
13c.sell()
14
15# change the price
16c.__maxprice = 1000
17c.sell()
18
19# using setter function
20c.setMaxPrice(1000)
21c.sell()
پس از اجرای برنامه بالا، خروجی به صورت زیر خواهد بود.
Selling Price: 900 Selling Price: 900 Selling Price: 1000
در برنامه بالا، کلاس Computer تعریف شد. از متد ()__init__ برای ذخیرهسازی حداکثر قیمت فروش یک کامپیوتر استفاده میشود. تلاش شده تا قیمت ویرایش شود. اگرچه، نمیتوان آن را تغییر داد زیرا پایتون با maxprice__ به عنوان یک خصیصه خصوصی برخورد میکند. برای تغییر مقدار، از یک تابع تنظیمکننده (setter function) برای مثال ()setMaxPrice استفاده میشود که قیمت را به عنوان یک پارامتر دریافت میکند.
چندریختی
«چند ریختی» (Polymorphism)، یک توانایی (در برنامهنویسی شیگرا) برای استفاده از رابط متداول، به چندین شکل (نوع داده) است. فرض میشود که کاربر نیاز به رنگ کردن یک شکل دارد، چندین گزینه برای شکل وجود دارد (مستطیل، مربع و دایره). میتوان از روش مشابهی برای رنگ کردن هر شکلی استفاده کرد.
این مفهوم، چندریختی نام دارد.
مثال ۵: استفاده از چند ریختی در پایتون
1class Parrot:
2
3 def fly(self):
4 print("Parrot can fly")
5
6 def swim(self):
7 print("Parrot can't swim")
8
9class Penguin:
10
11 def fly(self):
12 print("Penguin can't fly")
13
14 def swim(self):
15 print("Penguin can swim")
16
17# common interface
18def flying_test(bird):
19 bird.fly()
20
21#instantiate objects
22blu = Parrot()
23peggy = Penguin()
24
25# passing the object
26flying_test(blu)
27flying_test(peggy)
خروجی حاصل از اجرای قطعه کد بالا، به صورت زیر است.
Parrot can fly Penguin can't fly
در برنامه بالا، دو کلاس Parrot و Penguin تعریف شدهاند. هر یک از اینها، دارای متد متداول ()fly هستند. اگرچه، توابع آنها متفاوت هستند. برای پذیرش چندریختی، یک رابط مشترک ساخته شده است؛ در واقع، تابع ()flying_test که هر تابعی را میتواند بگیرد. سپس، اشیای blu و peggy به تابع ()flying_test انتقال داده میشوند.
این تابع به شیوه موثری عمل میکند. نکات کلیدی که باید پیرامون برنامهنویسی شیگرا به خاطر داشت:
- برنامهنویسی با استفاده از پارادایم شیگرا، آسان و موثر شده است.
- کلاس، قابل به اشتراکگذاری است؛ بنابراین، کدها قابل استفاده مجدد میشوند.
- کارایی برنامهنویسها با بهرهگیری از برنامهنویسی شیگرا، افزایش پیدا میکند.
- دادهها با «انتزاعیسازی داده» (Data Abstraction)، امن و مطمئن خواهند بود.
بسیار عالی و روان بود