آموزش پایتون - کلاس‌ها و اشیا

پایتون یک زبان برنامه‌نویسی شیءگرا است، به این معنی که بر اساس اصول مفاهیم شیءگرایی (OOP) بنا شده است. موجودیت‌های استفاده‌شده در یک برنامه پایتون، شیئی از یک کلاس مشخص هستند. به عنوان مثال، عددها، رشته‌ها، لیست‌ها، دیکشنری‌ها و سایر موجودیت‌های مشابه در یک برنامه، اشیائی از کلاس داخلی مربوط به خود هستند.

در پایتون، کلاسی به نام Object کلاس پایه یا والد برای تمام کلاس‌ها، چه داخلی و چه تعریف‌شده توسط کاربر است.

کلاس در پایتون چیست؟

در پایتون، یک کلاس یک موجودیت تعریف‌شده توسط کاربر (نوع داده) است که نوع داده‌هایی را که یک شیء می‌تواند داشته باشد و اقداماتی را که می‌تواند انجام دهد تعیین می‌کند. از کلاس به عنوان یک الگوی اولیه برای ساخت اشیاء استفاده می‌شود. به عنوان مثال، اگر بخواهیم کلاسی برای Smartphone (گوشی هوشمند) در یک برنامه پایتون تعریف کنیم، می‌توانیم از انواع داده مانند RAM، ROM، screen-size و اقداماتی مانند call و message استفاده کنیم.

ساخت کلاس‌ها در پایتون

کلیدواژه class برای ساخت یک کلاس جدید در پایتون استفاده می‌شود. نام کلاس بلافاصله پس از کلیدواژه class و به دنبال آن یک علامت دو نقطه قرار می‌گیرد، همان‌طور که در زیر نشان داده شده است −

class ClassName:
   'Optional class documentation string'
   class_suite
  • کلاس دارای یک رشته مستندات (docstring) است که می‌توان از طریق ClassName.__doc__ به آن دسترسی داشت.

  • بخش class_suite شامل تمام دستورات متشکله‌ای است که اعضای کلاس، ویژگی‌های داده‌ای و توابع را تعریف می‌کنند.

مثال

در ادامه مثالی از یک کلاس ساده در پایتون آورده شده است −

class Employee:
   'Common base class for all employees'
   empCount = 0

   def __init__(self, name, salary):
      self.name = name
      self.salary = salary
      Employee.empCount += 1
   
   def displayCount(self):
     print "Total Employee %d" % Employee.empCount

   def displayEmployee(self):
      print "Name : ", self.name,  ", Salary: ", self.salary
  • متغیر empCount یک متغیر کلاسی است که مقدار آن بین تمام نمونه‌های این کلاس به اشتراک گذاشته می‌شود. این متغیر به‌صورت Employee.empCount از داخل یا خارج کلاس قابل دسترسی است.

  • متد اول یعنی __init__() یک متد ویژه است که سازنده کلاس (Constructor) یا متد مقداردهی اولیه نامیده می‌شود و پایتون هنگام ساخت یک نمونه جدید از این کلاس، آن را فراخوانی می‌کند.

  • شما سایر متدهای کلاس را مانند توابع معمولی اعلام می‌کنید، با این استثنا که اولین آرگومان هر متد self است. پایتون آرگومان self را به طور خودکار به لیست اضافه می‌کند؛ نیازی نیست هنگام فراخوانی متدها آن را قرار دهید.

شیء چیست؟

به یک نمونه ساخته‌شده از یک کلاس مشخص در پایتون، شیء (Object) گفته می‌شود. هر شیء دارای ویژگی‌ها و متدهای خاص خود است که توسط کلاس آن تعریف شده‌اند.

وقتی یک کلاس ساخته می‌شود، فقط ساختار اشیاء را توصیف می‌کند. تخصیص حافظه زمانی رخ می‌دهد که یک شیء از روی کلاس نمونه‌سازی شود.

class object in python

در تصویر بالا، Vehicle نام کلاس است و Car، Bus و SUV اشیاء آن هستند.

ساخت اشیاء از کلاس‌ها در پایتون

برای ساخت نمونه‌هایی از یک کلاس، کلاس را با استفاده از نام آن فراخوانی کرده و هر آرگومانی را که متد __init__ آن می‌پذیرد پاس می‌دهید.

# This would create first object of Employee class
emp1 = Employee("Zara", 2000)
# This would create second object of Employee class
emp2 = Employee("Manni", 5000)

دسترسی به ویژگی‌های اشیاء در پایتون

شما با استفاده از عملگر نقطه روی شیء به ویژگی‌های آن دسترسی پیدا می‌کنید. متغیر کلاس نیز با استفاده از نام کلاس به‌صورت زیر قابل دسترسی خواهد بود −

emp1.displayEmployee()
emp2.displayEmployee()
print ("Total Employee %d" % Employee.empCount)

حال با کنار هم قرار دادن تمام مفاهیم −

class Employee:
   "Common base class for all employees"
   empCount = 0

   def __init__(self, name, salary):
      self.name = name
      self.salary = salary
      Employee.empCount += 1
   
   def displayCount(self):
     print ("Total Employee %d" % Employee.empCount)

   def displayEmployee(self):
      print ("Name : ", self.name,  ", Salary: ", self.salary)

# This would create first object of Employee class
emp1 = Employee("Zara", 2000)
# This would create second object of Employee class
emp2 = Employee("Manni", 5000)
emp1.displayEmployee()
emp2.displayEmployee()
print ("Total Employee %d" % Employee.empCount)

وقتی کد بالا اجرا می‌شود، نتیجه زیر را تولید می‌کند −

Name :  Zara , Salary:  2000
Name :  Manni , Salary:  5000
Total Employee 2

شما می‌توانید ویژگی‌های کلاس‌ها و اشیاء را در هر زمانی اضافه، حذف یا ویرایش کنید −

# Add an 'age' attribute
emp1.age = 7  
# Modify 'age' attribute
emp1.age = 8  
# Delete 'age' attribute
del emp1.age  

به جای استفاده از دستورات معمولی برای دسترسی به ویژگی‌ها، می‌توانید از توابع زیر نیز استفاده کنید −

  • getattr(obj, name[, default]) − برای دسترسی به ویژگی شیء.

  • hasattr(obj,name) − برای بررسی وجود یا عدم وجود یک ویژگی.

  • setattr(obj,name,value) − برای مقداردهی یک ویژگی. اگر ویژگی وجود نداشته باشد، ساخته می‌شود.

  • delattr(obj, name) − برای حذف یک ویژگی.

# Returns true if 'age' attribute exists
hasattr(emp1, 'age')   
# Returns value of 'age' attribute
getattr(emp1, 'age')    
# Set attribute 'age' at 8
setattr(emp1, 'age', 8) 
# Delete attribute 'age'
delattr(empl, 'age')    

ویژگی‌های داخلی کلاس در پایتون

هر کلاس در پایتون ویژگی‌های داخلی زیر را نگهداری می‌کند و مانند هر ویژگی دیگری می‌توان با استفاده از عملگر نقطه به آن‌ها دسترسی داشت −

شماره ویژگی‌ها و توضیحات
۱ __dict__

دیکشنری حاوی فضای نام (namespace) کلاس.

۲ __doc__

رشته مستندات کلاس یا None در صورت تعریف نشدن.

۳ __name__

نام کلاس.

۴ __module__

نام ماژولی که کلاس در آن تعریف شده است. این ویژگی در حالت تعاملی برابر با "__main__" است.

۵ __bases__

یک تاپل (چندتایی) که احتمالاً خالی است و شامل کلاس‌های پایه به ترتیب وقوع آن‌ها در لیست کلاس‌های پایه است.

مثال

برای کلاس Employee بالا، تلاش می‌کنیم به ویژگی‌های آن دسترسی پیدا کنیم −

class Employee:
   'Common base class for all employees'
   empCount = 0

   def __init__(self, name, salary):
      self.name = name
      self.salary = salary
      Employee.empCount += 1
   
   def displayCount(self):
     print ("Total Employee %d" % Employee.empCount)

   def displayEmployee(self):
      print ("Name : ", self.name,  ", Salary: ", self.salary)

print ("Employee.__doc__:", Employee.__doc__)
print ("Employee.__name__:", Employee.__name__)
print ("Employee.__module__:", Employee.__module__)
print ("Employee.__bases__:", Employee.__bases__)
print ("Employee.__dict__:", Employee.__dict__)

وقتی کد بالا اجرا می‌شود، نتیجه زیر را تولید می‌کند −

Employee.__doc__: Common base class for all employees
Employee.__name__: Employee
Employee.__module__: __main__
Employee.__bases__: ()
Employee.__dict__: {'__module__': '__main__', 'displayCount':
<function displayCount at 0xb7c84994>, 'empCount': 2, 
'displayEmployee': <function displayEmployee at 0xb7c8441c>, 
'__doc__': 'Common base class for all employees', 
'__init__': <function __init__ at 0xb7c846bc>}

کلاس‌های داخلی انواع داده در پایتون

همان‌طور که پیش‌تر اشاره شد، پایتون از پارادایم برنامه‌نویسی شیءگرا پیروی می‌کند. موجودیت‌هایی مانند رشته‌ها، لیست‌ها و انواع داده‌ها به یکی از کلاس‌های داخلی تعلق دارند.

اگر بخواهیم ببینیم کدام نوع داده به کدام کلاس داخلی تعلق دارد، می‌توانیم از تابع type() پایتون استفاده کنیم. این تابع یک نوع داده را می‌پذیرد و کلاس مربوط به آن را بازمی‌گرداند.

مثال

مثال زیر نحوه بررسی کلاس داخلی یک نوع داده مشخص را نشان می‌دهد.

num = 20
print (type(num))
num1 = 55.50
print (type(num1))
s = "TutorialsPoint"
print (type(s))
dct = {'a':1,'b':2,'c':3}
print (type(dct))
def SayHello():
   print ("Hello World")
   return
print (type(SayHello))

وقتی این کد را اجرا می‌کنید، کلاس‌های مربوط به انواع داده پایتون را نمایش می‌دهد −

<class 'int'>
<class 'float'>
<class 'str'>
<class 'dict'>
<class 'function'>

جمع‌آوری زباله (نابود کردن اشیاء) در پایتون

پایتون اشیاء غیرضروری (انواع داده داخلی یا نمونه‌های کلاس) را به طور خودکار حذف می‌کند تا فضای حافظه آزاد شود. فرآیندی که طی آن پایتون به صورت دوره‌ای بلوک‌هایی از حافظه را که دیگر مورد استفاده نیستند بازپس می‌گیرد، Garbage Collection (جمع‌آوری زباله) نامیده می‌شود.

زباله‌روب پایتون در طول اجرای برنامه اجرا می‌شود و زمانی تحریک می‌شود که تعداد ارجاعات (reference count) یک شیء به صفر برسد. تعداد ارجاعات یک شیء با تغییر تعداد نام‌های مستعاری که به آن اشاره می‌کنند، تغییر می‌یابد.

تعداد ارجاعات یک شیء زمانی افزایش می‌یابد که نام جدیدی به آن اختصاص داده شود یا در یک کانتینر (لیست، تاپل یا دیکشنری) قرار گیرد. تعداد ارجاعات شیء زمانی کاهش می‌یابد که با del حذف شود، ارجاع آن دوباره مقداردهی شود یا ارجاع آن از حوزه دسترسی (scope) خارج شود. وقتی تعداد ارجاعات یک شیء به صفر برسد، پایتون به طور خودکار آن را جمع‌آوری و پاکسازی می‌کند.

# Create object <40>
a = 40      
# Increase ref. count  of <40> 
b = a       
# Increase ref. count  of <40> 
c = [b]     

# Decrease ref. count  of <40>
del a       
# Decrease ref. count  of <40>
b = 100      
# Decrease ref. count  of <40>
c[0] = -1    

معمولاً متوجه زمان حذف یک نمونه استفاده‌نشده و بازپس‌گیری فضای آن توسط زباله‌روب نخواهید شد. اما یک کلاس می‌تواند متد ویژه __del__() را که تخریب‌کننده (destructor) نامیده می‌شود پیاده‌سازی کند؛ این متد زمانی فراخوانی می‌شود که نمونه در آستانه نابودی قرار دارد. این متد ممکن است برای پاکسازی منابع غیرحافظه‌ای استفاده‌شده توسط یک نمونه به کار رود.

مثال

تخریب‌کننده __del__() نام کلاس نمونه‌ای را که در آستانه نابودی است چاپ می‌کند، همان‌طور که در بلوک کد زیر نشان داده شده است −

class Point:
   def __init__( self, x=0, y=0):
      self.x = x
      self.y = y
   def __del__(self):
      class_name = self.__class__.__name__
      print (class_name, "destroyed")

pt1 = Point()
pt2 = pt1
pt3 = pt1
# prints the ids of the obejcts
print (id(pt1), id(pt2), id(pt3))
del pt1
del pt2
del pt3

پس از اجرا، کد بالا نتیجه زیر را تولید می‌کند −

135007479444176 135007479444176 135007479444176
Point destroyed

مخفی‌سازی داده‌ها (Data Hiding) در پایتون

ویژگی‌های یک شیء ممکن است خارج از تعریف کلاس قابل مشاهده باشند یا نباشند. شما باید ویژگی‌ها را با پیشوند زیرخط دوگانه (double underscore) نام‌گذاری کنید تا آن ویژگی‌ها مستقیماً برای بیرون از کلاس قابل مشاهده نباشند.

مثال

class JustCounter:
   __secretCount = 0
  
   def count(self):
      self.__secretCount += 1
      print self.__secretCount

counter = JustCounter()
counter.count()
counter.count()
print counter.__secretCount

وقتی کد بالا اجرا می‌شود، نتیجه زیر را تولید می‌کند −

1
2
ERROR!
Traceback (most recent call last):
  File <main.py>", line 11, in <module>
AttributeError: 'JustCounter' object has no attribute '__secretCount'

پایتون با تغییر داخلی نام برای گنجاندن نام کلاس، از این اعضا محافظت می‌کند. شما می‌توانید به این ویژگی‌ها به‌صورت object._className__attrName دسترسی داشته باشید. اگر خط آخر خود را به‌صورت زیر جایگزین کنید، کد کار خواهد کرد −

print(counter._JustCounter__secretCount)

وقتی کد بالا اجرا می‌شود، نتیجه زیر را تولید می‌کند −

1
2
2

پیشرفت مطالعه: وضعیت خوانده‌شدن این درس فقط در همین مرورگر ذخیره می‌شود؛ بدون نیاز به حساب کاربری.