۱/۲۰/۱۳۸۹

Zen of Python

جملات زیر اصول راهنمای طراحی  پایتون هستند. جالبن
>>> import this
The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!
>>>

۱۲/۲۱/۱۳۸۸

معرفی یک ماژول > doctest


doctest یکی از ماژولهای استاندارد پایتون است که به منظور سهولت در تست کردن کد پایتون (کپی شده از python shell) طراحی شده است. به طور کلی این ماژول برای سه منظور ممکن است استفاده شود:

  1.  بررسی به روز بودن docstring های یک ماژول با استفاده از مقایسه ی نتایج تست های ثبت شده در docstring ها با مقدار بدست آمده هنگام تست 
  2.  بررسی صحت درست کارکردن مثالهای موجود در یک فایل تست
  3. نوشتن اسناد آموزشی برای یک  package
 در این پست به شکلی ساده برخی از قابلیتهای این ماژول توضیح داده میشود. در واقع تنها به رابط اصلی و پایه ی آن (Basic API) میپردازیم.

تابع فاکتوریل را در نظر بگیرید:

def factorial(n):
    if n<0: return "Only a natural number!"
    return (1 if n==0 else n*factorial(n-1))

حالا امتحانش میکنیم:

>>> factorial(5)
120
>>> factorial(3)
6
>>> factorial(-2)
'Only a natural number!'
>>>  
میتوانیم این نتایج را به عنوان توضیحی درمورد خروجی این متود در docstring آن قرار دهیم:

def factorial(n):
    '''
    Returns factorial of a natural number
    for example:
    >>> factorial(5)
    120
    >>> factorial(3)
    6
    >>> factorial(-2)
    'Only a natural number!'
    >>>

    '''    
    if n<0: return "Only a natural number!"    
    return (1 if n==0 else n*factorial(n-1))

این نتایج به درستی محاسبه شده اند. به عبارت دیگر هرگاه این تابع به ازای مقادیری که در تست های موجود در docstring آن آمده اجرا شود همان خروجی هایی که در docstring آمده نمایان خواهند شد.
این تابع را در ماژول test.py ذخیره میکنیم.
برای اطمینان حاصل کردن از این درستی کافی است متود testmod را در انتهای ماژول test.py صدا بزنیم:

import doctest
doctest.testmod()
دوباره ماژول را اجرا میکنیم...
.
.
.
هیچ اتفاقی نمیافتد! خوب این یعنی این که نتایج موجود در تمام docstring های موجود در test.py به درستی محاسبه شده اند ☺
میتوان جزییات مربوط به این تست را این گونه دید:



حال کمی متود factorial را تغییر میدهیم تا در صورت بروز خطاهای
احتمالی در ورودی خروجی مناسبی بازگرداند:

def factorial(n):
    '''
    Returns factorial of a natural number
    for example:
    >>> factorial(5)
    120
    >>> factorial(3)
    6
    >>> factorial(-2)
    'Only a natural number!'
    >>>
    '''
    if n<0: return "Not negative integers!"
    if int(n) is not n:
        return "Must be an integer!"
    return (1 if n==0 else n*factorial(n-1))

دقت کنید doctest یک docstring را اینگونه برداشت میکند:

>>> import test #test.py contains the factorial method
>>> print doctest.testsource(test,'test.factorial')
# Returns factorial of a natural number
# for example:
factorial(5)
# Expected:
## 120
factorial(3)
# Expected:
## 6
factorial(-2)
# Expected:
## 'Only a natural number!'

>>>

دوباره ماژول را اجرا میکنیم...

>>>
**********************************************************************
File "C:\Users\SEVEN\Documents\test.py", line 9, in __main__.factorial
Failed example:
    factorial(-2)
Expected:
    'Only a natural number!'
Got:
    'Not negative integers!'
**********************************************************************
1 items had failures:
   1 of   3 in __main__.factorial
***Test Failed*** 1 failures.
>>>

نتیجه ی اخلاقی اینجا این است که هرگاه هرچیزی (مثلا یک متود) را تغییر میدهید، docstring مربوطه را نیز به روز کنید!☻
با استفاده از testmod تمام docstring های موجود در یک ماژول جستجو میشوند.(شیءهایی که import شده اند جستجو نمیشوند)

حالا میخواهیم یک فایل آموزشی درباره ی این ماژول درست کنیم. یک فایل txt با نام how_to یعنی how_to.txt میسازیم با این محتوا:

This is a tutorial documentation for test.py module

this module contains the following objects:
    factorial method

That's it for now :D

how to use factorial method:

first you have to import it like this
>>> from test import factorial

then you can use it this way:
>>> factorial(5)
120

if you enter a negative number, it can handle it:
>>> factorial(-3)
'Not negative integers!'

also if you enter a non-integer, you'll receive this message:
>>> factorial(5.5)
'Must be an integer!'

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

>>> doctest.testfile("C:\Users\SEVEN\Documents\\how_to.txt")
TestResults(failed=0, attempted=4)

همانطور که دیدید testfile تمام خطوط قابل اجرا در فایل how_to را بررسی کرد و در انتها نشان داد که همگی به درستی نوشته شده بودند.

دو متود testmod و testfile ساده ترین راههای استفاده از doctest هستند. از آنجایی که این پست هم تنها قصد معرفی این ماژول را داشت بیش از این پیش نمیرویم :دی

اطلاعات بیشتر درباره ی این دو متود را اینجا خواهید یافت.
مزیت ها و اشکالات doctest نیز به طور خلاصه اینجا گردآوری شده اند.

موفق باشید ☺

۱۲/۱۳/۱۳۸۸

برنامه نویسی شیء گرا - قسمت ششم > متودهای خاص


تا اینجا با متودهایی چون __init__ و __str__ آشنا شدید. این متودها معمولا مستقیم صدا زده نمیشوند و در مواقع خاصی عمل میکنند. مثلا __str__ هنگام پرینت کردن یک شیء صدا زده میشود. انواع دیگری از این متودهای خاص وجود دارد که در این پست یکی دیگر از آنها را معرفی میکنم.


> object.__repr__() or repr(object) or `object`

repr مخفف representation یا همان "نمایش" یک شیء است. برای این که بفهمیم هر شیء چه چیزی را نمایش میدهد کافیست نام آن را در Python Shell صدا بزنیم:

>>> a='I am string of a'
>>> a
'I am string of a'
>>> b=12.3
>>> b
12.300000000000001
>>> c=range(10)
>>> c
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>>

هنگامی که یک شیء جدید تعریف میکنیم به حالت پیش فرض، هر نمونه از آن، نوع و مکان خود در حافظه را نمایش میدهد:
>>> class Point(object): pass

>>> p=Point()
>>> p                                               <__main__.Point object at 0x02012290>
>>> 

خروجی متود repr همواره رشته ایست از آنچه شیء نمایش میدهد:

>>> repr(p)
'<__main__.Point object at 0x02012290>'
>>> p.__repr__()
'<__main__.Point object at 0x02012290>'
>>>
>>> b=12.3
>>> repr(b)
'12.300000000000001'
>>> c=range(10)
>>> c.__repr__()
'[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]'
>>> d=set([1,2,3,3])
>>> `d`
'set([1, 2, 3])'
>>>


خب، پس همانند متود __str__ خروجی این متود یک رشته است. در صورتی که متود __str__ برای یک شیء تعریف نشده باشد ولی __repr__ تعریف شده باشد، __repr__ به جای __str__ نیز صدا زده میشود (عکس این برقرار نیست!)

>>> class Point(object):
        def __init__(self,x,y):
       
    self.x=x
       
    self.y=y
   
    def __repr__(self):
       
    return str(self.x)+','+str(self.y)

   
>>> p=Point(2,3)
>>> print p
2,3
>>> str(p)
'2,3'
>>> repr(p)
'2,3'
>>> p
2,3
>>> 

همانطور که دیدید حالا که ما متود __repr__ برای Point را override کردیم (یعنی تعریف آنرا تغییر دادیم)، دیگر p ، نوع و مکان خود در حافظه را نمایش نمیدهد. ما تعیین کردیم که هر Point مختصات خود را نمایش دهد.
حالا متود __str__ را هم برای Point تعریف میکنیم و __repr__ را هم کمی تغییر میدهیم:

>>> class Point(object):
        def __init__(self,x,y):
       
    self.x=x
       
    self.y=y
       
   
    def __str__(self):
       
    return str(self.x)+','+str(self.y)
   
    def __repr__(self):
       
    return 'Point(x=%d,y=%d)'\
                   %(self.x,self.y)

   
>>> p=Point(2,3)
>>> print p
2,3
>>> str(p)
'2,3'
>>> p
Point(x=2,y=3)
>>> repr(p)
'Point(x=2,y=3)'
>>>

حالا که ما __str__ را هم override کرده ایم، دیگر متود repr به جای آن صدا زده نمیشود، در ضمن ما تعیین کردیم که هر Point ، نوع و مختصات خود را نمایش دهد. به این ترتیب هر Point نمایشی ساده و قابل فهم دارد.
علاوه بر قابل فهم تر کردن نمایش یک شیء، یکی دیگر از فواید متود repr، قابلیت شناخته شدن یک شیء برای استفاده در متود eval است.

با استفاده از متود eval میتوان یک دستور قابل اجرا که در قالب یک رشته نوشته شده را اجرا کرد:

>>> eval('abs(-1)')
1
>>> a=eval('range(10)')
>>> a==range(10)
True
>>> a
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>>
>>> eval('1+1')
2

ورودی متود eval همانند خروجی متود repr یک رشته است.
اشیاء از پیش تعریف شده در پایتون مثل اعداد، رشته ها، لیست ها و ... طوری نمایش داده میشوند که با استفاده از متود eval میتوان آنها را دوباره تولید کرد (کپی کرد):

>>> a=2
>>> b=eval(repr(a))
>>> b
2
>>> a==b
True
>>> repr(a)
'2'
>>> lst=range(10)
>>> repr(lst)
'[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]'
>>> lst_copy=eval(repr(lst))
>>> lst_copy
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>>
>>> p=Point(2,3)
>>> p
Point(x=2,y=3)
>>> p2=eval(repr(p))
>>> p2
Point(x=2,y=3)
>>> p2.x
2
>>> p2.y
3
>>> 

همانطور که دیدید من نیز متود __repr__ را به گونه ای override کرده ام که در صورت evaluate کردن نمایش یک Point، یک نمونه با همان مشخصات تولید شود.

با استفاده از متود repr میتوان هر شیء را به یک رشته تبدیل کرد. میتوان از این رشته ها در انواع تست ها، کپی کردن، ذخیره سازی در پایگاههای داده و ... بهره جست.
برای انواع خاصی از اشیاء همچون اعداد صحیح، لیست ها و ...، خروجی این متود همان خروجی متود str است. 

>>> str(1.0)==repr(1.0)
True
>>> str(3.2)==repr(3.2)
False
>>> print str(3.2),repr(3.2)
3.2 3.2000000000000002
>>> str(range(10))==repr(range(10))
True
>>> 
>>> print str('Good \n Luck')
Good
 Luck
>>> print repr('Good \n Luck')
'Good \n Luck'


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

موفق باشید ☺☻
 

۱۲/۰۶/۱۳۸۸

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

در این قسمت نوع خاصی از متودها در پایتون به نام 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 در سایت رسمی پایتون اینجا موجود است.

موفق باشید ☺

۱۱/۲۵/۱۳۸۸

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

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

class MyMath(object):

    @staticmethod
    def fac(n):
        '''factorial of a number (a recursive method)'''
        return 1 if not n else n*MyMath.fac(n-1)


>>> MyMath.fac(5)
120
>>> aInstance=MyMath()
>>> aInstance.fac(5)
120
>>> 


همونطور که دیدیداصلا نیازی به نمونه گرفتن از کلاس نبود.

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

class Timer():
    '''
    An easy to use timer which

    reminds me of a VB8 stopwatch :D
    It uses python time module
    '''
    #double underlines __ here make
    #__time a private  attribute
    __time=0

    #making reset a static method, there is
    #no more need for a self argument.

    #instead reset=staticmethod(reset)
    #I use a decorator
    @staticmethod
    def reset():
        '''

        updates the starting time
        with local time
        '''
        from time import time
        Timer.__time=time()



    @staticmethod
    def elapsed():
        '''

        elapsed seconds since last reset() call
        '''
        from time import time
        return time()-Timer.__time

 
حالا من این کلاس را در فایل myassets.py و در این آدرس "E:\My Projects" ذخیره میکنم. 
حالا اگر بخواهیم در هر برنامه ای که در همین آدرس ذخیره شده از این کلاس استفاده کنیم کافیست بنویسیم


from myassets import Timer

Timer.reset()
# a block of code

#
print Timer.elapsed(), 'Seconds!'


اما اگر برنامه در آدرس دیگری ذخیره شده باشد مینویسیم
 
import sys
sys.path.append('E:\My Projects')
#now we can import any module from this address

#the rest is just the same

#instead of importing only Timer class
#I import everything that can be imported!
#into this module using *
from myassets import *

Timer.reset()
# a block of code
#
print Timer.elapsed(), 'Seconds!'


 برای اطلاعات بیشتر در مورد ماژول sys به اینجا و در مورد ماژول time به اینجا مراجعه کنید.

موفق باشید ☻ 

 

۱۱/۲۲/۱۳۸۸

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

 بعضي از اشياء ويژگيهايي دارند که فقط حالات خاصي رو ميپذيرند. مثلا شعاع یک توپ نمیتواند 0 يا منفي باشد. ميتوانيم اين محدوديتها را براي هر ويژگي اي  که لازم دارد اعمال کنيم. با همين مثال توپ شروع ميکنيم. اول شعاع توپ را طوري تعريف ميکنيم که فقط موقع تعريف توپ مقدار دهی شود و بعد غير قابل تغيير باشد.
class Ball(object):
    '''represents a ball object'''
  
    def __init__(self,radius):
        #we make radius a private attribute by
        #adding __ at its beginning
        self.__radius=radius
   

    #we call this a getter method for __radius
    def get_radius(self)
        return self.__radius


    #we
make a property read-only by only defining 
    #a getter method for it
    #I also add a docstring for this property
    radius=property(get_radius,

                    doc='''radius of the ball''')
 


>>> myball=Ball(5)
>>> myball.radius
5
>>> myball.radius=6

Traceback (most recent call last):
  File "", line 1, in
    myball.radius=6
AttributeError: can't set attribute
>>>
>>> myball.radius
5
 ما الان یک ویژگی غیر قابل تغییر تعریف کردیم(در اصطلاح یک "ریدونلی پراپرتی")
حالا قابلیت تغییر دادن هم اضافه می کنیم با این محدودیت که شعاع توپ باید مثبت باشد

class Ball(object):

    def __init__(self,radius): self.__radius=radius
   
    def get_radius(self):
        return self.__radius




    #we call this a setter method for __radius
    def set_radius(self,radius):
        if radius>0:
            #if it is a valid value then assign it
            self.__radius=radius
        else:
            #no assignments happen here
            #printing a message to warn user
            print 'can\'t assign this value,',\

                  'radius must be positive'

    #both getter and setter methods are included
    radius=property(get_radius,set_radius)


>>> myball=Ball(5)
>>> myball.radius
5
>>> myball.radius=6
>>> myball.radius
6
>>> myball.radius=-1
can't assign this value, radius must be positive
>>> myball.radius
6
>>> 

اگر دقت کرده باشيد در تابع سازنده ویژگی شعاع رو با __ شروع کرديم. اين باعث ميشود که اين "اتريبوت" پوشيده بماند يعني نميشود بيرون از کلاس تغييرش داد یا حتی مقدارش را گرفت.  ببينيد

>>> myball.__radius
Traceback (most recent call last):
  File "", line 1, in
    myball.__radius
AttributeError: 'Ball' object has no attribute '__radius'
>>>

یکی از ایرادهایی که در در برنامه نویسی شیء گرا به پایتون وارده همین بحث خصوصی سازی ویژگیها و متود هاست. در حقیقت وقتی اسم یک متود یا ویژگی را با __ شروع کنیم پایتون فقط بااسم دیگری ذخیره اش میکند! دقت کنید
>>> myball._Ball__radius
6
>>> myball._Ball__radius=-1
>>> myball.radius
-1
>>>

این به این معنی است که عملا در پایتون همه ی ویژگیها و متود های یک کلاس همگانی (پابلیک) اند
راه قشنگ تری هم برای تعریف پراپرتی ها هست و آن استفاده از "دکوراتور" هاست. اینجا معادل مثال اول را با این روش مینویسیم 
class Ball(object):

    def __init__(self,radius): self.__radius=radius

    @property
    def radius(self):
        '''radius of the ball'''
        return self.__radius 


>>> myball=Ball(5)
>>> myball.radius
5
 
هر پراپرتی میتواند 3 متود "گتر"، "ستر" و "دیلیتر" داشته باشد به علاوه ی یک "داک استرینگ". الان من شعاع توپ را به صورت یک پراپرتی کامل بااستفاده از "دکوراتور" ها تعریف میکنم.

class Ball(object):

    def __init__(self,r): self.__radius=r

    @property
    def radius(self):
        '''radius of the ball'''
        return self.__radius

    @radius.setter
    def radius(self,r):
        if r>0: self.__radius=r
        else: print 'must be positive'

    @radius.deleter
    def radius(self):
        #this method will delete __radius attribute
        #and so will its related property
        del self.__radius
 
>>> myball=Ball(5)
>>> myball.radius=0
must be positive
>>> del myball.radius
>>> myball.radius
Traceback (most recent call last):
  File "", line 1, in
    myball.radius
  File "C:\Users\SEVEN\Desktop\basic oop\basic oop.py", line 55, in radius
    return self.__radius
AttributeError: 'Ball' object has no attribute '_Ball__radius'
>>>

با حذف کردن یک پراپرتی در واقع متود دیلیترش صدا زده میشود.

برای اطلاعات بیشتر در مورد پراپرتی ها به سایت رسمی پایتون اینجا و یا اینجا مراجعه کنید. در ضمن اگه هر سوال یا پیشنهادی هم دارید به صورت نظر به همین پست بفرستید.
موفق باشید ☺



۱۱/۲۰/۱۳۸۸

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



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

class Point(object):
    x=None
    y=None
فعلا نقطه رو فقط با دو ویژگی تعریف کردیم. حالا با این تعریف دو تا نقطه میسازیم

>>> p1=Point()
>>> p2=Point()
>>> p1.x=3
>>> p1.y=5
>>> print p1.x, p1.y
3 5
>>> p2.y=6
>>> p2.x=1
>>> p2.x+p2.y
7
>>> 

تو خط اول گفتیم پی 1 یه نقطس و تو خط های سوم و چهارم ویژگیهاشو مشخص کردیم. بعد تو خط پنجم اومدیم به ترتیب اونارو پرینت کردیم
میشه همزمان با تعریف کردن  پی 1 ، ویژگیهاشم مشخص کرد. در ضمن مثل موقعی که یه متغیر رو پرینت میکنیم و مقدارش چاپ میشه ، یه نمونه از یه کلاس رو هم میتونیم مستقیم پرینت کنیم و تعیین کنیم چیش چاپ شه! دقت کنید

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

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

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

>>> p3=Point(4,12)
>>> print p3
4 12
>>> str(p3)
'4 12'
>>>  
 
دقت کنید در تمامی توابع یه کلاس به جای اولین ورودی،  اون نمونه ای از کلاس که تابع رو صدا میزنه قرار میگیره. مثلا تو مثال بالا تو خط اول، پی3 به جای اولین آرگومان قرار گرفت و 4 و 12 به ترتیب دومین و سومین ورودیهای تابع سازنده میشن

به سه دستور زیر دقت کنید. اینا معادلن


>>> str(p3) ; p3.__str__() ; Point.__str__(p3)
'4 12'
'4 12'
'4 12'
>>> 

همیشه بهتره کدتونو جوری بنویسید که اگه کسی خواست ازش استفاده کنه یا خودتون در آینده خواستین ازش استفاده کنین به راحتی قابل فهم باشه. راهش اینه که از کامنت ها و "داک استرینگ" ها استفاده کنیم. الان دوباره نقطه رو تعریف میکنیم و این بار در مورد کدش توضیحم میزاریم. در ضمن یه متود (تابع) هم بهش اضافه میکنیم که فاصله ی این نقطه از یه نقطه ی دیگه رو حساب کنه

class Point(object):
    '''represents a point on a 2D screen'''
   
    def __init__(self,x,y):
        '''
        x is the coordinate along x-axis
        y is the coordinate along y-axis
        '''
        self.x=x
        self.y=y

    def __str__(self):
        '''

        point's coordinates in string seperated
        by a white space
        ''' 
        return str(self.x)+' '+str(self.y)

    def distance_from(self,aPoint):
        '''
        calculates distance of aPoint

        from this point.
        (returns a floating point number)
        '''
        #we need sqrt
in our calculation
        from math import sqrt
        #using Pythagorean theorem
        dx=self.x-aPoint.x
        dy=self.y-aPoint.y
        return sqrt(dx**2+dy**2)

حالا متود جدیدو امتحان میکنیم

>>> p=Point(3,5)
>>> o=Point(0,0)
>>> p.distance_from(o)
5.8309518948453007
>>> 

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

>>> print p.distance_from.__doc__

        calculates distance of aPoint from this point
        (returns a floating point number)
       
>>> print Point.__doc__
represents a point on a 2D screen
>>>  

فک کنم برای قسمت اول کافی باشه☺