در این سری مقالات آموزش پایتون، از پایه و ابتدا مفاهیم پایتون رو یاد میگیریم و نکاتی که برای یادداشت برداری لازم است را در این سری مقالات ذکر میکنم که هم بتونم مرور کنم و هم اینکه شاید برای برخی افراد که وارد این مسیر میشوند مفید واقع بشه.
در کل هدف این سری مقالات یادگیری پیشرفته پایتون از پایه است و سعی میکنم هر مورد که یاد میگیرم را در اینجا به اشتراک بذارم.
در این بخش در رابطه با مفاهیم شی گرایی یا Object Oriented Programming صحبت کنیم. OOP به زبانهای برنامه نویسی شی گرایی که از آبجکتها استفاده میکنند اشاره میکند که ویژگیهای ارث بری (Inheritance)، مخفی کردن اطلاعات (Information hiding) و polymorphism را دارد.
در زبانهای برنامه نویسی OOP مفاهیم زیر وجود دارد که تسلط بر آنها به ما کمک زیادی میکند.
- Encapsulation
- Inheritance
- Polymorphism
- Abstraction
یک Object نشان دهنده یک Entity است که ۳ ویژگی زیر را دارد:
۱. Identity: یک هویت و نام منحصر به فرد به object میدهد.
۲. State: ویژگیهای یک object را نمایش میدهد. (properties of an object)
۳. Behavior: پاسخ و رفتار یک object در پاسخ به سایر objectها را نمایش میدهد.

حالا که مفهوم آبجکت را باهم بررسی کردیم لازم است در رابطه با مفهوم دیگری به نام Class صحبت کنیم. در واقع کلاس یک نقشه یا طرح کار برای Object است.
وقتی بخواهیم یک کلاس تعریف کنیم از کلمه کلیدی class استفاده میکنیم و کلاس مانند یک سازنده object برای ایجاد objectها است. کلاس Objectهایی را تعریف میکند که properties و methods های یکسانی دارند.
Methodها در واقع functionهایی هستند که داخل کلاس تعریف میشوند و متدها توسط Objectها فراخوانی میشوند تا رفتاری یا اقدامی را در بخشهای مختلف انجام دهند.
در زبان برنامه نویسی پایتون یک متد سازنده به اسم __init__ وجود دارد که وقتی یک آبجکت فراخوانی میشود به صورت اتوماتیک این متد فراخوانی میشود و در واقع متد سازنده نام دارد و در بسیاری از زبانهای دیگر با نام construct شناخته میشود.
در مثال زیر self در متد init به آبجکت جدیدی که ساخته میشود اشاره میکند ولی در سایر متدهای کلاس، به نمونه ای از Object اشاره می کند که Method آن فراخوانی شده است.
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def myfunc(self):
print("Hello my name is " + self.name)
p1 = Person("John", 36)
print(p1.name)
print(p1.age)
p1.myfunc()
نکته مهم: پارامتر self به نمونه فعلی ایجاد شده کلاس اشاره میکند که به Methods , propertiesها که متعلق له کلاس هستند دسترسی دارد. میتوان نام آن را هرچیز دیگری بذارید ولی باید اولین پارامتر از هر متدی باشد.
نکته: در زبان برنامه نویسی پایتون نیازی نیست که بعد از استفاده و ایجاد یک object آن را منحصرا حذف کنیم. در واقع زبان برنامه نویسی پایتون به صورت اتوماتیک وقتی که هیچ رفرنسی به آبجکت وجود نداشته باشد آن را حذف میکند. در واقع پایتون garbage collection دارد.
The process by which Python periodically frees and reclaims blocks of memory that no longer are in use is called Garbage Collection. Python’s garbage collector runs during program execution and is triggered when an object’s reference count reaches zero.
Python Access Modifier
برای دسترسی به Methodها و Propertyهای یک کلاس ما با استفاده از تعیین Access هر مورد مشخص میکنیم که چه صورت در برنامه قابل دسترسی هستند.
در زبان برنامه نویسی پایتون ما ۳ نوع Access Modifier داریم:
۱. Public: مانند مثالهایی که تا الان بیان کردیم که به صورت معمولی و در دسترس هستند.
۳. Protected: اعضای یک کلاس فقط توسط کلاسهایی که از آن ارث بری کرده اند قابل دسترس هستند. برای مشخص کردن اینکه یک property از نوع protected است یا خیر باید یک علامت آندرلاین _ قبل از آن قرار دهیم.
class Cat:
# protected access modifiers
ـname = None
ـage = None
ـbreed = None
۳. Private: اعضای کلاس فقط توسط خود کلاس در دسترس هستند. برای مشخص کردن اینکه یک property از نوع private است یا خیر باید یک علامت دو آندرلاین __ قبل از آن قرار دهیم.
class student :
counter = 0
def __init__ (self, name, fathersname, age):
student.counter +=1
self.name = name
self.fathersname = fathersname
self.age = age
self._roll_no = 'A2022/{}/{:003d}'.format(self.name [:3].upper () ‚student.counter) # Protected
self.__file_no = 'A2022/{}/{:003d}'.format(self.name.upper () ,student.counter) # Private
Python Inheritance
ارث بری یا Inheritance به ما اجازه میدهد که تمام متدها و ویژگیهایی که در یک کلاس داریم با ارث بری در کلاس دیگری استفاده کنیم. Inheritance را میتوان به چند نوع تقسیم کرد:
- Single Level Inheritence: یک کلاس از یک کلاس دیگر ارث بری میکند.
- Multilevel Inheritence: یک ساب کلاس از یک کلاس دیگری که خودش از کلاس دیگری ارث بری کرده، ارث بری میکند.
- Multiple Inheritence: یک کلاس از بیش از یک کلاس ارث بری میکند.
- Hierarchical Inheritence: یک کلاس، ساب کلاسهای مختلفی دارد که از آن ارث بری میکنند.
وقتی که یک Base Class یا Parent Class داریم و سایر کلاسها (Child Class) میخواهند از آن ارث بری کنند. برای مثال فرض کنید یک کلاس به اسم Person داریم و به صورت زیر است:
class Person:
def __init__(self, fname, lname):
self.firstname = fname
self.lastname = lname
def printname(self):
print(self.firstname, self.lastname)
x = Person("John", "Doe")
x.printname()
حالا ما میخواهیم یک کلاس Student بسازیم و همین ویژگی ها را دارد پس از آن ارث بری میکند به صورت زیر:
class Student(Person):
pass
x = Student("Michael", "Andish")
x.printname()
همانطور که میدونیم کلاس Parent تابع __init__ دارد و اگر بخواهیم در Child Class هم اضافه کنیم در واقع آن را Overwrite میکند پس باید دوباره پارامترها را به Parent Class پاس دهیم. وقتی اینکار را انجام میدهیم که بخواهیم در Child Class موارد دیگری را به تابع سازنده __init__ اضافه کنیم.
class Student(Person):
def __init__(self, fname, lname):
Person.__init__(self, fname, lname)
اگر به صورت زیر کلاس دیگری داشته باشیم در واقع حالت Multilevel Inheritence را خواهیم داشت. در واقع کلاس زیر به متدها و پراپرتیهای دو کلاس student , person دسترسی دارد.
class TopGradeStudent(Student):
pass
Polymorphism
- Polymorphism یک کلمه یونانی است که به معنای اشکال مختلف است.
- توانایی یک پیام برای نمایش بیش از یک شکل به عنوان چند شکلی شناخته می شود.
- مثال: زن می تواند همزمان مادر، همسر، دختر، معلم و کارمند باشد.

برای مثال Built-in functionی به نام len به صورت polymorphism پیاده سازی شده است:
print(len("Programiz"))
print(len(["Python", "Php", "C#"]))
print(len({"Name": "Michael", "Address": "Netherlands"}))
و یا در مثال زیر میتوانید متوجه شوید که به چه صورتی میتوانیم آن را پیاده سازی کنیم:
class Cat:
def __init__(self, name, age):
self.name = name
self.age = age
def info(self):
print(f"I am a cat. My name is {self.name}. I am {self.age} years old.")
def make_sound(self):
print("Meow")
class Dog:
def __init__(self, name, age):
self.name = name
self.age = age
def info(self):
print(f"I am a dog. My name is {self.name}. I am {self.age} years old.")
def make_sound(self):
print("Bark")
cat1 = Cat("Kitty", 2.5)
dog1 = Dog("Fluffy", 4)
for animal in (cat1, dog1):
animal.make_sound()
animal.info()
animal.make_sound()
Encapsulation
در فرآیند Encapsulation داده ها و اعضای یک فانکشن به یک واحد مشخص بایند میشوند! به این فرآیند مخفی سازی هم میگویند و از دسترسی غیر مجاز به داده ها و متدها پیشگیری میکند، به عنوان یک محافظ عمل می کند که دسترسی مستقیم به متغیرها و متدها را محدود می کند به همین دلیل به آن پنهان کردن داده ها میگویند.
class Encapsulation:
def __init__ (self, a, b, c):
self.public = a
self._protected = b
self.__private = c
Abstraction
Abstraction یک ویژگی است که تنها جزئیاتی که لازم است کاربر ببیند را نمایش میدهد، برای مثال وقتی که شما دکمه ای روی کیبورد فشار میدهد و کاراکتری روی صفحه چاپ میشود را میبینید و اینکه چطور این اتفاق می افتد لزومی ندارد کاربر نهایی متوجه آن باشد، به این مفهوم Abstraction میگوییم.
در زبان برنامه نویسی پایتون Abstraction کلاسها فقط مانند یک تمپلت برای سایر کلاسها عمل میکنند. یک کلاس Abstract فقط می تواند ارث بری شود.
وقتی میخواهیم یک Abstract Class تعریف کنیم ابتدا باید ماژول abc را ایمپورت کنیم به صورت زیر:
from abc import ABC
class abs_class(ABC):
#abstract methods
همانطور که میدانیم داخل Abstract Class میتوانیم هر تعداد method یا propery تعریف کنیم. در مثال زیر ما ابتدا ماژول abc را ایمپورت کردیم و همچنین متد abstract را هم تعریف کرده ایم.
from abc import ABC, abstractmethod
class Absclass(ABC):
def print(self,x):
print("Passed value: ", x)
@abstractmethod
def task(self):
print("We are inside Absclass task")
class test_class(Absclass):
def task(self):
print("We are inside test_class task")
class example_class(Absclass):
def task(self):
print("We are inside example_class task")
#object of test_class created
test_obj = test_class()
test_obj.task()
test_obj.print(100)
پس از اینکه کاربر از هر دو کلاس test_class و example_class یک object ایجاد کند و متد task() را برای هر دوی آنها فراخوانی کند، hidden defination برای متدهای task() در هر دو کلاس وارد عمل می شوند، این hidden definationها از دید کاربر پنهان است.
متد انتزاعی task() از کلاس انتزاعی Absclass در واقع هرگز فراخوانی نمی شود.
اما متد print یک متد abstract نیست و هر زمان فراخوانی بشود از کلاس Absclass فراخوانی میشود.