مشخصات مقاله
-
9268
-
0.0
-
8826
-
0
-
0
شی گرایی در زبان پایتون / Python Object-Oriented
مروری بر واژگان و اصطلاحات تخصصی OOP
- Class (کلاس): مجموعه ای از آبجکت ها که ویژگی های یکسان دارند یک کلاس را می سازند. به عبارت دیگر یک نمونه ی اختصاصی یا user-defined که اجازه ی ساخت آبجکت یا نمونه های متعدد از یک الگو مشترک را می دهد. هر کلاس واحدی مجزا از اپلیکیشن است که داده هایی را در قالب متغیرهای عضو که attribute نام داشته و عملیات که در قالب method تعریف می شود را دربرمی گیرد. همان طور که گفته شد، attribute ها اعضایی از کلاس هستند که داده های را در خود نگه می دارند (class variable و instance variable) و متدها نیز رفتارهای کلاس بوده و عملیات خاصی را انجام می دهند. جهت دسترسی به متدها و متغیرهای عضو کلاس کافی است از عملگر نقطه استفاده نمایید.
- class variable (متغیرهای عضو کلاس): متغیری که بین تمامی نمونه های ایجاد شده از کلاس مشترک می باشد، متغیر عضو کلاس یا class variable خوانده می شود. متغیرهای عضو داخل بدنه ی کلاس اما خارج از حوزه ی اختصاصی متدهای آن کلاس (scope) تعریف می شوند. Class variable یا متغیرهای عضو کلاس نسبت به متغیرهای نمونه ی ایجاد شده از کلاس یا همان instance variable بسیار کم تر مورد استفاده قرار می گیرد.
- Data member: یک class variable یا instance variable که داده های مربوط به یک کلاس و آبجکت های ساخته شده از روی آن را دربرمی گیرد.
- function overloading: تخصیص و تعریف چندین رفتار برای تابعی یکسان. به عبارت دیگر، ایجاد چندین نسخه ی مختلف از تابعی با نام یکسان. حال این عملیاتی که تابع انجام می دهد به نوع آبجکت ها یا آرگومان هایی که شرکت دارند، وابسته است.
- instance variable: یک متغیر که داخل حوزه ی اختصاصی یا بدنه ی متد تعریف شده و تنها به نمونه ی جاری از کلاس تعلق دارد.
- Inheritance (وراثت): انتقال ویژگی های یک کلاس به کلاس هایی که از آن مشتق می شوند را در اصطلاح Inheritance یا وراثت می گویند.
- instance: به یک آبجکت واحد از کلاس در اصطلاح Instance گفته می شود. برای مثال، آبجکتی به نام obj که متعلق به کلاسی به نام Circle می باشد، در واقع یک نمونه (ساخته شده از) کلاس Circle (که الگویی برای ساخت آبجکت ها می باشد) است.
- Instantiation (نمونه سازی از کلاس): به ساخت آبجکت یا نمونه ای از کلاس مورد نظر Instantiation گویند.
- method: همان تابع که داخل بدنه یا حوزه ی اختصاصی کلاس اعلان می شود.
- Object: عبارت است از یک نمونه ی یکتا که از روی کلاس مورد نظر ساخته می شود. یک آبجکت می تواند علاوه بر data member ها (متغیرهای عضو کلاس و متغیرهای عضو نمونه ی ایجاد شده از کلاس)، متد نیز دربرداشته باشد.
- Operator overloading: تخصیص چندین رفتار به عملگری یکسان. به عبارت دقیق تر، یک نمونه ی خاص از چندریختی است که عملگرها می توانند بر اساس آرگومان ها و پارامترهای ورودی پیاده سازی متفاوتی داشته باشد.
تعریف کلاس
دستور class همان طور که از اسم آن مشخص است، یک کلاس جدید تعریف می کند. اسم کلاس بلافاصله پس از کلیدواژه ی class و عملگر دو نقطه درج می شود:
class ClassName: 'Optional class documentation string' class_suite
کلاس، داخل ساختمان خود یک docstring ( یک رشته ی ثابت که در کد برنامه لحاظ شده و عملکردی مشابه comment دارد و برای توضیح هدف اصلی کد مورد استفاده قرار می گیرد ، اما بر خلاف comment معمولی، در زمان اجرای برنامه همچنان باقی مانده و برای کاربر نمایش داده می شود.) دارد که با درج دستور ClassName.__doc__ در دسترس توسعه دهنده قرار می گیرد.
class_suite دربردارنده ی تمامی دستورات تشکیل دهنده ی کلاس از جمله دستورات تعریف اعضای کلاس، attribute ها و توابع می باشد.
مثالدر زیر نمونه ای از کلاس ساده ی پایتون را مشاهده می کنید:
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 یک class variable است که مقدار آن بین تمامی نمونه های ایجاد شده از کلاس جاری مشترک می باشد. جهت دسترسی به این متغیر، چه از داخل کلاس یا خارج از آن، کافی است از دستور Employee.empCount استفاده نمایید.
- اولین متد __init__() ، تابع سازنده یا متد مقداردهنده ی اولیه (constructor یا initialization method) است که پایتون آن را به هنگام ساخته شدن نمونه ی جدید از کلاس، فراخوانی می کند.
- سایر متدهای کلاس مانند توابع عادی تعریف می شوند با این تفاوت که اولین آرگومان ارسالی به متد پارامتر self می باشد. Python به صورت خودکار آرگومان مزبور را به لیست اضافه می کند و نیازی نیست که توسعه دهنده به هنگام فراخوانی متد آن را به عنوان پارامتر به طور صریح لحاظ کند.
ایجاد آبجکت های نمونه (ساخت آّبجکت یا نمونه از روی کلاس)
به منظور ایجاد نمونه هایی از یک کلاس، توسعه دهنده آن را با استفاده از اسم کلاس فراخوانی کرده و سپس پارامترهای مورد نظر را به تابع سازنده یا constructor ارسال نمایید.
"This would create first object of Employee class"
emp1 = Employee("Zara", 2000)
"This would create second object of Employee class"
emp2 = Employee("Manni", 5000)
دسترسی به attribute ها () کلاس
جهت دسترسی به attribute های یک آبجکت، کافی است از اسم آبجکت و عملگر نقطه استفاده نمایید. class variable (متغیر عضو کلاس) به صورت زیر، با استفاده از اسم کلاس و عملگر نقطه قابل دسترسی می باشد:
emp1.displayEmployee() emp2.displayEmployee() print "Total Employee %d" % Employee.empCount
حال تمامی مفاهیم را با هم در یک مثال به صورت کاربردی مورد استفاده قرار می دهیم:
#!/usr/bin/python
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
توسعه دهنده می تواند attribute های کلاس ها و آّبجکت ها را هر زمان که لازم دانست ویرایش (اضافه، حذف و غیره ...) کند:
emp1.age = 7 # Add an 'age' attribute. emp1.age = 8 # Modify 'age' attribute. del emp1.age # Delete 'age' attribute.
می توان علاوه بر روش معمول دسترسی به attribute ها، از توابع زیر برای فراخوانی و دستیابی به attribute مورد نظر استفاده کرد:
- متد getattr(obj, name[, default]): جهت دسترسی به متغیر عضو یا attribute از آبجکت مورد نظر.
- hasattr(obj,name): جهت بررسی صحت وجود یک attribute در آبجکت مد نظر.
- متد setattr(obj,name,value): به منظور مقداردهی و تنظیم یک attribute مورد استفاده قرار می گیرد. اگر attribute مورد نظر وجود نداشت، متد نام برده آن را ایجاد کرده و مقداردهی می کند.
- متدdelattr(obj, name) : به منظور حذف attribute فراخوانی می شود.
hasattr(emp1, 'age') # Returns true if 'age' attribute exists getattr(emp1, 'age') # Returns value of 'age' attribute setattr(emp1, 'age', 8) # Set attribute 'age' at 8 delattr(empl, 'age') # Delete attribute 'age'
Attribute های درون ساخته ی کلاس
کلاس های پایتون attribute های درون ساخته و پیش فرضی دارند که به وسیله ی عملگر نقطه به راحتی برای توسعه دهنده قابل دسترسی می باشند.
این attribute ها عبارتند از:
- __dict__: یک attribute از نوع داده ای dictionary که دربردارنده ی namespace کلاس می باشد.
- __doc__: رشته ی مستندسازی و درج توضیحات در کلاس / documentation string یا در صورتی که تعریف نشده باشد، None.
- __name__: اسم کلاس.
- __module__: اسم ماژولی که در آن کلاس تعریف شده است. در حالت تعاملی یا interactive mode، این attribute "__main__" است. (interactive mode: یک امکان مبتنی بر خط دستور است که قابلیت اجرا و پردازش کدهای پایتون را فراهم می آورد. زمانی که اسکریپت می نویسید با فشردن کلید enter برنامه ی مفسر آن را به صورت خودکار اجرا می کند.)
- __bases__: یک متغیر چندتایی (از نوع tuple) تهی که دربردارنده ی کلاس های پایه، به ترتیبی که در لیست کلاس های پایه قید شده است، می باشد.
با کد زیر سعی می کنیم به تمامی attribute های نام برده در کلاس حاضر دسترسی پیدا کنیم:
#!/usr/bin/python
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':
, 'empCount': 2,
'displayEmployee': ,
'__doc__': 'Common base class for all employees',
'__init__': }
حذف آبجکت های غیرضروری از حافظه (مدیریت حافظه یا Garbage collection)
پایتون تمامی آبجکت های بلااستفاده را به صورت خودکار، جهت آزاد سازی منابع، از حافظه پاک می کند. فرایندی که پایتون به واسطه ی آن در فواصل زمانی معین قطعاتی از حافظه را که دیگر مورد استفاده نیستند بازپس گرفته و آبجکت های ذخیره شده در آن را پاک می کند، در اصطلاح garbage collection خوانده می شود.
Garbage collector پایتون به هنگام اجرای برنامه فعال می گردد و زمانی که reference count (تعداد دفعات ارجاع به آبجکت و استفاده از آن) به صفر می رسد، اجرا شده و آبجکت های بلااستفاده را از حافظه حذف می کند. لازم به ذکر است زمانی که نام های مستعاری (aliases) که به یک آبجکت اشاره دارند، تغییر می کنند، reference count یک آبجکت نیز به تبع تغییر می نماید.
Reference count یک آبجکت هنگامی افزایش می یابد که اسم جدیدی به آن آبجکت تخصیص یافته یا داخل یک ظرف (container) همچون list، tuple یا dictionary قرار داده شود. زمانی که آبجکت مورد نظر با کلیدواژه ی del حذف می شود یا reference اشاره کننده به آن به آبجکت دیگری تخصیص می یابد و یا از حوزه (scope) خارج می شود، reference count آبجکت کاهش می یابد.
همچنین زمانی که reference count یک آبجکت به صفر می رسد، پایتون آن را به صورت خودکار collect کرده و از حافظه حذف می نماید.
a = 40 # Create object <40> b = a # Increase ref. count of <40> c = [b] # Increase ref. count of <40> del a # Decrease ref. count of <40> b = 100 # Decrease ref. count of <40> c[0] = -1 # Decrease ref. count of <40>
اغلب زمانی که garbage collector یک نمونه ی بلااستفاده (orphaned instance و سرگردان) را حذف کرده و منابع اختصاص یافته به آن را آزاد می سازد، شما متوجه این عملیات پس زمینه ای نمی شوید. یک کلاس همچنین می تواند متد __del__() را پیاده سازی کند که در اصطلاح destructor (حذف کننده ی نمونه ی کلاس از حافظه) خوانده می شود. این متد به هنگام حذف نمونه ی مورد نظر از حافظه صدا زده شده و آن نمونه ی بلااستفاده یا سرگردان را از حافظه پاک می نماید.
مثالتابع __del__() اسم کلاسی که نمونه ی مورد نظر از روی آن ساخته شده را به هنگام حذف آبجکت از حافظه، در نمایشگر چاپ می کند.
#!/usr/bin/python
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
print id(pt1), id(pt2), id(pt3) # prints the ids of the obejcts
del pt1
del pt2
del pt3
کد فوق پس از اجرا خروجی زیر را تولید می کند:
3083401324 3083401324 3083401324 Point destroyed
بهتر است که کلاس های خود را داخل فایل مجزا تعریف نموده، سپس آن ها را با استفاده از دستور import وارد متن برنامه ی اصلی (main program) نمایید.
مبحث وراثت و class inheritance
می توانید بجای اینکه کلاسی را از از پایه ایجاد کنید، آن را از یک کلاس آماده و از پیش موجود به راحتی مشتق نمایید. برای این منظور کافی است اسم کلاس پدر (parent) را داخل پرانتز بعد از اسم کلاس مورد نظر درج کنید.
کلاس مشتق (child) attribute ها و ویژگی های کلاس پدر/پایه (parent) را به ارث برده و شما می توانید به آن ها به سادگی دسترسی داشته باشید گویا این attribute ها داخل خود کلاس فرزنده تعریف شده اند. کلاس مشتق/فرزند سپس این قابلیت را دارد تا اعضا (متغیرهای عضو کلاس و متدها) را به طور دلخواه بازنویسی (override) نماید.
ساختار دستوری و سینتکس
کلاس های مشتق شبیه به کلاس های پایه یا پدر خود تعریف می شوند، با این تفاوت که لیستی از اسم کلاس های پایه (که از آن ارث بری صورت گرفته)، پس از اسم کلاس جدید درج می شود:
class SubClassName (ParentClass1[, ParentClass2, ...]): 'Optional class documentation string' class_suiteمثال
#!/usr/bin/python
class Parent: # define parent class
parentAttr = 100
def __init__(self):
print "Calling parent constructor"
def parentMethod(self):
print 'Calling parent method'
def setAttr(self, attr):
Parent.parentAttr = attr
def getAttr(self):
print "Parent attribute :", Parent.parentAttr
class Child(Parent): # define child class
def __init__(self):
print "Calling child constructor"
def childMethod(self):
print 'Calling child method'
c = Child() # instance of child
c.childMethod() # child calls its method
c.parentMethod() # calls parent's method
c.setAttr(200) # again call parent's method
c.getAttr() # again call parent's method
کد فوق پس از اجرا نتیجه ی زیر را برمی گرداند:
Calling child constructor Calling child method Calling parent method Parent attribute : 200
به همین روال می توان یک کلاس جدید را همزمان از چندین کلاس پدر مشتق نمود:
class A: # define your class A ..... class B: # define your class B ..... class C(A, B): # subclass of A and B .....
می توان با فراخوانی توابع issubclass() یا isinstance() رابطه ی بین دو کلاس و نمونه را بررسی کرد.
- چنانچه پارامتر sub واقعا کلاسی مشتق شده از پارامتر sup باشد، تابع بولیissubclass(sub, sup) مقدار true را برمی گرداند.
- چنانچه پارامتر obj واقعا نمونه ای از پارامتر Class باشد، آنگاه تابع بولی isinstance(obj, Class) مقدار true را در خروجی بازگردانی می نماید.
بازنویسی متدها (overriding)
توسعه دهنده این امکان را دارد که توابع ارث برده شده از کلاس پدر را بازنویسی نمایند. یکی از دلایل بازنویسی متد کلاس پدر می تواند نیاز به افزودن قابلیت جدید به تابع مورد نظر در بدنه ی کلاس فرزند و مشتق شده باشد.
مثال#!/usr/bin/python
class Parent: # define parent class
def myMethod(self):
print 'Calling parent method'
class Child(Parent): # define child class
def myMethod(self):
print 'Calling child method'
c = Child() # instance of child
c.myMethod() # child calls overridden method
کد فوق پس از اجرا نتیجه ی زیر را در خروجی تولید می کند:
Calling child method
معرفی متدهایی جهت بازنویسی
جدول زیر تعدادی توابع با قابلیت های کلی در اختیار شما قرار می دهد که می توانید آن ها را داخل بدنه ی کلاس های خود بر اساس نیاز بازنویسی نمایید:
Operator overloading
فرض کنید کلاس جدیدی به نام Vector ایجاد کرده اید که نشانگر vector های دو بعدی می باشد. اگر بخواهیم آن ها را با عملگر + با یکدیگر جمع کنیم، چه رخ می دهد؟ پایتون قطعا واکنش نشان داده و خطا می گیرد.
برای رفع این مشکل می توانید یک متد __add__ داخل کلاس مورد نظر تعریف کنید که عمل جمع دو vector را انجام دهد. با این کار عملگر مزبور طبق انتظار عمل خواهد کرد:
مثال#!/usr/bin/python
class Vector:
def __init__(self, a, b):
self.a = a
self.b = b
def __str__(self):
return 'Vector (%d, %d)' % (self.a, self.b)
def __add__(self,other):
return Vector(self.a + other.a, self.b + other.b)
v1 = Vector(2,10)
v2 = Vector(5,-2)
print v1 + v2