‏نمایش پست‌ها با برچسب وراثت. نمایش همه پست‌ها
‏نمایش پست‌ها با برچسب وراثت. نمایش همه پست‌ها

۱۲/۰۶/۱۳۸۸

برنامه نویسی شیء گرا - قسمت پنجم

در این قسمت نوع خاصی از متودها در پایتون به نام classmethod ها را تعریف میکنم. منبع اصلی این قسمت با کلیک کردن روی عنوان پست قابل دسترس است و من اینجا تقریبا مطالب آن را ترجمه میکنم. (با کمی تصرف!)

ابتدا مفهوم وسیله ی نقلیه را تعریف میکنیم. با ارث بردن از آن مفاهیم موتور، اتومبیل و کامیون را تعریف میکنیم. خوب، حالا که چی؟! :دی
میخواهیم تعداد موتورها، اتومبیل ها، کامیونها و همچنین تعداد کل وسایل نقلیه را به راحتی و تنها با یک متغیر total در اختیار داشته باشیم.
تعداد هر نوع وسیله را با استفاده از متود set_total تعیین میکنیم و برای نمایش آن از متود print_total استفاده میکنیم.


#an example of an old-style class
class Vehicle:
    '''
    represents a vehicle.
    total is the
number
    of all vehicles
    '''
    total=0

    @classmethod
    def print_total(cls):
        '''
        prints total of cls kind vehicles!
        e.g:
        >>> Bike.set_total(3)
        >>> Bike.print_total()
        3
        '''
        print cls.total

    @classmethod
    def set_total(cls, value):
        '''
        sets total of cls kind vehicles!
        e.g:
        >>> Bike.set_total(3)
        '''
        cls.total = value
        #updating the total
        #number of all vehicles
        Vehicle.total+=value

    @staticmethod
    def vehicle_total():
        '''prints the total
        number of all vehicles'''
        print Vehicle.total

#using 'pass' keyword, leaving
#the class with no more definition
class Bike(Vehicle): pass

class Car(Vehicle): pass

class Truck(Vehicle): pass


خوب، همانطور که دیدید برای تعریف یک classmethod مثل تعریف staticmethod از دکوراتورها استفاده کردیم.  
دقت کنید که اولین ورودی هر classmethod را cls نامگذاری کردیم (مانند self این هم لزومی ندارد cls نامگذاری شود ولی معمولا این اسم را برمیگزینند! :دی)
این ورودی همانند self هنگام صدازدن متود مقدار دهی نمیشود اما فرقش با self این است که self نمونه ای از کلاس است که تابع را صدا میزند اما cls خود کلاسی (و نه نمونه ی آن) است که تابع را فرامیخواند، حال چه از طریق یک نمونه ی آن صدازده شود چه مستقیم از خود کلاس (شبیه staticmethod)


>>> Bike.set_total(3)   # Bike.total = 3
>>> Car.set_total(5)    # Car.total = 5
>>> Truck.set_total(2)  # Truck.total = 2
>>>
>>> b = Bike()
>>> c = Car()
>>> t = Truck()
>>>
>>> b.print_total(); c.print_total(); t.print_total()
3
5
2
>>> #
following results are just the same as above
...
... Bike.print_total(); Car.print_total(); Truck.print_total()
3
5
2
>>> 
>>> Vehicle.total #total of vehicles
10
>>> b.vehicle_total()
#total of vehicles
10
>>> Car.vehicle_total()
#total of vehicles
10
>>> Car.total #total of cars
5
>>>

همانطور که دیدید، همانند یک staticmethod فرقی نمیکند که یک classmethod را از نمونه ای از کلاس یا خود آن فرا بخوانیم.
توجه کنید که تفاوت staticmethod با classmethod در این است که اولی به طور کلی مستقل از خود کلاس است و تنها درون آن تعریف شده( به عبارت دیگر تفاوت آن با متودی همنام در بیرون از کلاس در namespace آنها است) اما دومی تنها مستقل از نمونه های یک کلاس است و نه خود آن.
 
 
با کمی ور رفتن با این مفاهیم بهتر میفهمیدشون :دی
برای اطلاعات بیشتر درباره ی classmethod به سایت رسمی پایتون اینجا یا اینجا مراجعه کنید. هر سوالی هم داشتید میتوانید به صورت پاسخ به همین پست بپرسید.
 
موفق باشید ☺

۱۲/۰۲/۱۳۸۸

برنامه نویسی شیء گرا - قسمت چهارم > وراثت


همانطور که در دنیای واقعی برخی مفاهیم از مفاهیم کوچکتر بوجود می آیند یا برخی اشیاء ویژگیهای برخی دیگر را به ارث میبرند و یا تکامل یافته ی اشیای دیگرند، در برنامه نویسی شیء گرا هم این امکان وجود دارد و این مهم ترین بخش از برنامه نویسی شیء گراست.

در قسمت اول، مفهوم نقطه در صفحه را تعریف کردیم. با استفاده از آن به راحتی میتوان مفهوم نقطه در فضا را هم تعریف کرد. دقت کنید

class Point(object):
   
    def __init__(self,x,y):
        self.x=x
        self.y=y

    def __str__(self):
        return str(self.x)+' '+str(self.y)


#instead on inheriting object
#this time I inherit Point class
class Point3D(Point):
    '''
    represents a point in the space
    inherits Point class
    '''

    #overriding constructor method
    def __init__(self,x,y,z):
        #calling constructor of supper class
        #from this instance (self)
        super(Point3D,self).__init__(x,y)
        self.z=z

    #overriding __str__ method
    def __str__(self):

        #calling __str__ method of
        #the base class (Point)
        #it will return str(self.x)+' '+str(self.y)
        XandY=Point.__str__(self)

        return XandY+' '+str(self.z)

    #this is a new method I add for
Point3D
    def vector_len(self):
        '''
        returns the length of the vector
        which represents this point
        '''
        from math import sqrt
        x,y,z=self.x,self.y,self.z
        return sqrt(x**2+y**2+z**2)


ابتدا بجای object نام کلاسی که از آن ارث میبریم را مینویسیم. با همین کار ساده میتوانیم از تمامی ویژگیها و متودهای کلاس پایه (base class) در این کلاس استفاده کنیم. (به کلاس پایه superclass نیز میگویند)
در مواقعی خاص برای صدا زدن متودهای کلاس پایه از تابع super استفاده میکنیم. این تابع همواره دو ورودی میگیرد که اولی نام کلاس و دومی نمونه ای از کلاس است که تابع را صدا میزند (همان self)
اگر متودی همنام با یکی از متودهای کلاس پایه تعریف کنیم جایگزین آن در این کلاس میشود. یعنی اگر از این کلاس صدا زده شود متود جدید فراخوانده میشود و نه متود همنام آن در کلاس پایه! به این کار override کردن یک متود میگویند. در مثال بالا تابع سازنده و تابع __str__ "اوور راید" شده اند.



>>> p=Point3D(1,2,3)
>>> print p
1 2 3
>>> p.x
1
>>> p.z
3
>>> p1=Point(4,5)
>>> p1.x
4
>>> print p1
4 5
>>> p.vector_len()
3.7416573867739413
>>> Point3D.__doc__
'\n    represents a point in the space\n    inherits Point class\n    '





یک مثال هم از اشیاء:

در این مثال از ماژول turtle استفاده میشود که خارج از بحث این قسمت است. برای آشنایی با این ماژول به اینجا و برای آشنایی بیشتر به اینجا مراجعه کنید.

میخواهیم مفهوم توپ در صفحه را تعریف کنیم. برای اینکار به سادگی میتوان توپ را حالت خاصی از یک نمونه از کلاس turtle.Turtle در نظر گرفت که به شکل توپ(دایروی) درآمده است. در واقع برای تعریف توپ این کلاس را به ارث میبریم.

#importing Turtle class
from turtle import Turtle

#inheriting from Turtle class
class Ball(Turtle):
    '''represents a 2D ball on the screen'''

    #overriding Turtle's constructor method
    def __init__(self,radius,color='black'):
        '''
        radius is the radius of the ball in pixels
        color is name of the color of the ball
        (optional argument)
        '''
        #first we have to initialize the associated
        #Turtle instance for this ball
        super(Ball,self).__init__()
        #the above line is nearly the
        #same as Turtle.__init__(self)


        #2D balls are circle shaped :D
        self.shape('circle')

        #initializing size and color attributes
       
        #this float division here is because
        #turtlesize is nearly one tenth of
        #its real value in pixels
        self.turtlesize(radius/10.)
        self.color(color)

        #I want my ball to leave

        #no trace on the screen
        self.penup()

    def move(self,teta=0,step=10):
        '''
        moves the ball 'step' points on 
        'teta' direction
        (both arguments are optional)
        '''
        #setting the angle of the ball to teta
        self.setheading(teta)
        #forwarding step points on

        #the new direction (teta)
        self.forward(step)



در مثال بالا توپ بسیار ساده تعریف شد و تنها یک متود برای حرکت آن تعریف کردیم. البته تمامی توابع کلاس Turtle نیز برای این توپ قابل استفاده هستند. (به ارث برده شده اند)

>>>
>>> myball=Ball(20,'blue')
>>> myball.move()
>>> myball.move(teta=45)
>>> myball.move(step=100,teta=60)
>>> myball.speed('lowest')
>>> myball.forward(-100)
>>> myball.speed(1)
>>> myball.move(45,45)
>>> myball.position()
(48.89,38.89)
>>> myball.circle(30)
>>>




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

موفق باشید ☺