فصل هفتم

فصلی هفت که در بخش Tutorial اسناد پایتون بطور مفصل شرح داده شده است. متاسفانه من ۳بار این فصل رو بطور کامل ترجمه کردم و بک آپ گرفتم ولی بطورشگفت انگیزی اکنون هیچی از آن مطالب در دست نمی باشد. برای اینکه آموزش پایه مان نارس نباشد تصمیم گرفتم یه نگاه به کل این بخش در اسناد اصلی بیاندازم و تمام مثال هایش را با شرح توضیحاتی هر چند نا منطبق با محتویات این اسناد بیان کنم.

نحو تعریف کلاس
ساده ترین شکل تعریف کلاس چیزی شبیه زیر است:

class ClassName:
<statement-1>
.
.
.
<statement-N>

تعریف کلاس مثل تعریف تابع است کلمه کلیدی class و پس از آن نام کلاس و بعد متد ها و صفات کلاس .
به توابع درون کلاس متد و به متغیر های درون کلاس صفت یا خواص می گویند.
اشیای کلاس
در زیر یک کلاس با متد f و صفت i تعریف کرده ایم

class MyClass:
    """A simple example class"""
    i = 12345
    def f(self):
        return 'hello world'

برای  استفاده از این کلاس ابتدا باید یک نمونه از روی آن یسازیم:

x = MyClass()

کلاس ها ممکن است یک متد ویژه ای داشته باشند بنام __init__()

def __init__(self):
    self.data = []

وقتی کلاسی متد __init__() را تعریف می کنند این متد به محض فراخوانی کلاس بطور اتوماتیک اجرا می شود:

x = MyClass()

البته متد __init__() برای انعطاف پذیری آرگومان هایی نیز دریافت می کند. برای مثال:

>>> class Complex:
...     def __init__(self, realpart, imagpart):
...         self.r = realpart
...         self.i = imagpart
...
>>> x = Complex(3.0, -4.5)
>>> x.r, x.i
(۳٫۰, -۴٫۵)

self در اینجا بخود کلاس اشاره می کند . معمولا همراه با init بکار می رود.
خب حالا با این نمونه کلاس ها چکاری می توانیم انجام بدهیم؟ به کلاس MyClass در بالا بر می گردیم و یک نمونه بنام x از روی ان می سازیم . کلا ۲ نوع خواص برای هر کلاس داریم، یک خواص داده ای و دوم متدها .
خواص داده ای متناظر با عضو های داده ای در C++ هستند. خواص داده ای نیازی ندارند که حتما درون کلاس تعریف شوند چون یک متغیر هستند پس بمحض مقدار دهی به آنها بوجود می آیند، این یکی از ویژگی های ذاتی برتر زبان برنامه نویسی پایتون است. برای مثال اگر نمونه x از روی کلاس MyClass ساخته باشیم مطابق با کد زیر ما یک صفت کانتر با مقدار دهی ۱ درون نمونه x ساخته ایم و سپس به انجام عملیات خود ادامه می دهیم و سرانجام مقدار ۱۶ چاپ خواهد شد.

x.counter = 1
while x.counter < 10:
x.counter = x.counter * 2
print x.counter
del x.counter

متد آیتم ها
معمولا یک متد سمت راست شی فراخوانده می شود:
x.f()
درمثال MyClass این متد رشته ‘hello world’ را باز خواهد گرداند. البته می شود شی متد را در یک متغیر ذخیره کنیم و در زمان مناسب این چنین فرا بخوانیم:

xf = x.f
while True:
    print xf()

متدی که فرا خوانده شده است دقیقا چگونه روی می دهد؟ شما در بالا متد x.f را بدون آرگومان فرا خوانده خوانده اید، پس تکلیف آرگومان self که در تعریف متد درون کلاس آماده است چه می شود؟ پایتون برای توابعی که با آرگومان تعریف شده اند و ولی هنگامی فراخوانی تابع بدون آرگومان فرا خوانده می شوند استثنایی را برپا می کند حتی اگر این آرگومان در عمل بکار گرفته نشود…
در واقع ممکن است شما پاسخ را حدس زده باشید: وقتی آرگومان self مورد استفاده قرار می گیرد در واقع این ارگومان اشاره به خود کلاس می کند و کاربرد ان برای پیدا کردن دیگر متد ها و خواص در داخل شی است.
برای مثال در تعریف کلاس زیر:

class Hi():
    def __init__(self):
        print sayHello()

    def sayHello():
        return 'Hello World'

اگر یک شی از این کلاس را اجرا کنیم استثنای ErrorName می دهدو هشدار می دهد که تابعی بنام sayHello تعریف نشده است. دلیل آن هم این می باشد که تابع پس از خطی که فراخوانده شده ، تعریف شده است:

h = Hi()
Traceback (most recent call last):
File "<pyshell#11>", line 1, in <module>
h = Hi()
File "<pyshell#10>", line 3, in __init__
print sayHello()
NameError: global name 'sayHello' is not defined

برای رفع این مشکل :

class Hi():
    def __init__(self):
        print self.sayHello()
    def sayHello(self):
        return 'Hello World'
>>> h = Hi()
Hello World

وقتی مفسر به خط print self.sayHello() می رسد و پیشوند self را می بیند متوجه می شود که باید تابعی به نام sayHello در ادامه کد تعریف شده باشد پس به اجرای کد ادامه می دهد. خب فکر کنم که این مثال بسیار عالی ای باشد که متوجه امر شده باشید.
متد ها نیز می توانند متد های دیگر را با استفاده از آرگومان self فراخوانی کنند:

class Bag:
    def __init__(self):
        self.data = []
    def add(self, x):
        self.data.append(x)
    def addtwice(self, x):
        self.add(x)
        self.add(x)

وراثت

البته یکی از ویژگی های زبان پایتون پشتیبانی کلاس از وراثت است. نحو برای کلاس مشتق شده شبیه زیر است:

class DerivedClassName(BaseClassName):
<statement-1>
.
.
.
<statement-N>

نام BaseClassName باید در یک دامنه که شامل تعریف کلاس مشتق است، تعریف شده باشد.  زمانی که کلاس پایه در یکی دیگر از ماژول تعریف شده است:

class DerivedClassName(modname.BaseClassName):

هنگامی که شیی از کلاس ساخته می شود، کلاس پایه فرا خوانده می شود. این روش برای برطرف کردن خواص ارجاع  داده شده بکار می رود: اگر کلاس متد یا صفتی از کلاس جاری درخواست شود و این متد یا صفت در کلاس تعریف نشده باشد به کلاس پایه مراجعه می شود شاید متد و صفت درخواست شده در انجا پیدا شود

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

>>> class a():
name ='iraj'
>>> class b(a):
family= 'jelodari'
>>> c = b()
>>> c.family
'jelodari'
>>> c.name
'iraj'

در مثال بالا کلاس a کلاس پایه است و کلاس b کلاس مشتق. از روی کلاس مشتق که همان b می باشد شی C را ساخته ایم. صفت فامیلی را در این آیتم جستجو کرده ام این صفت در خود کلاس b حضور دارد سپس صفت نام را جستجو کرده ام که در کلاس b نیست ولی در کلاس پایه a حضور دارد.
پایتون ۲ تابع توکار برای کار با وراثت دارد:
isinstance() برای چک کردن نوع شی یا نمونه بکار می رود: مثلا isinstance(obj, int) پاسخ True را فقط هنگامی بر می گرداند که شی obj از نوع int باشد
issubclass() برای چک کردن یک کلاس بکار می رود: issubclass(bool, int)مقدار True را باز می گرداند زیراکه bool ساب کلاسی (زیر کلاسی) از int است. issubclass(unicode, str) مقدار False را باز می گرداند زیراکه unicode ساب کلاسی از str نیست.
وراثت چندگانه
پایتون شکلی از وراثت چندگانه را به خوبی پشتیبانی می کند. تعریف کلاسی با چند کلاس پایه شبیه زیر:

class DerivedClassName(Base1, Base2, Base3):
<statement-1>
.
.
.
<statement-N>

در این تعریف اگر صفتی در کلاس مشتق شده پیدا نشد، از چپ به راست ، ابتدا کلاس Bace1 جستجو می شود و اگر باز هم پیدا نشد Bace2 و سپس..
در سبک جدید کلاس ها مرتب سازی تجزیه تحلیل متد بصورت پویایی با فراخوانی super() تغییر کرده است. این رویکرد در بعضی از زبان های وراثتی چندگانه دیگر نیز با عنوان call-next-method شناخته شده است.
خب این تابع سوپر چکار می کند؟ چجور کار می کند؟ ۲ مثال در زیر می زنم که به راحتی و زیبایی کارکرد تابع سوپر را در وراثت روشن می کند:

>>> class A(object):
    def routine(self):
        print "A.routine()"
>>> class B(A):
    def routine(self):
       print "B.routine()"
     super(B,self).routine()
>>> b.routine()
B.routine()
A.routine()

در مثال بالا کلاس پایه A و کلاس مشتق شده B را داریم در هر۲ کلاس متد routine تعریف شده است. وقتی یک نمونه از کلاس B را اجرا کنیم متد routine که در این کلاس هست اجرا می شه، برای استفاده از وراثت باید از تابع سوپر استفاده کنیم بدین ترتیب که آرگومان اول سوپر نام کلاس مشتق در اینجا Bو آرگومان دوم نوع کلاس مشتق که از A می باشد سپس متد پس از تابع سوپر متد routine را فرا می خوانیم که این بار از کلاس پایه ی A گرفته می شود.
مثال دوم:

class Base(object):
    def __init__(self):
        print "Base created"

class ChildA(Base):
    def __init__(self):
        Base.__init__(self)

class ChildB(Base):
    def __init__(self):
        super(ChildB, self).__init__()
        print ChildA(),ChildB()

در مثال بالا کلاس پایه Bace و کلاس های فرزند A و B را داریم در کلاس A متد init از کلاس پایه Bace فراخوانده شده است و در کلاس B از تابع سوپر که نام کلاس B و نوع آن را گرفته است و سپس متد init را فراخوانده است. همانطور که مشاهده می کنید نتیجه هر۲ کلاس فرزند A وB یکسان می باشد و تفاوتی باهم ندارند.

6 دیدگاه برای «فصل هفتم»

  1. خیلی عالی کارت من که هر روز دارم سر میزنم و مطالبت رو هم از اول اول دارم میخونم امیدوارم مطالب خوب و عالی از PyQt بزاری که خیلی ازش خوشم میاد

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

پاسخ دهید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *