ทำความเข้าใจกับ Python Decorators

Python decorators เป็น feature หนึ่งของภาษา Python ซึ่ง feature นี้ไม่ใช่ Decorator pattern นะครับ เพียงแต่ว่าสามารถนำไปใช้ทำ pattern แบบนั้นได้

ความสามารถของมันก็คือ มันสามารถที่จะเปลี่ยนแปลงพฤติกรรมการทำงานของฟังก์ชั่นหรือคลาสที่เราเอา decorator ที่เขียนขึ้นไปแปะไว้ได้ ประโยชน์ของมันคือเราไม่ต้องเข้าไปแก้ไขการทำงานของฟังก์ชั่นหรือคลาสนั้นๆ โดยไม่จำเป็น หรือถ้าเราไม่อยากจะเข้าไปแก้ไขการทำงานนั้นๆ เลย เราก็ใช้ decorator เข้ามาช่วยครับ บทความนี้จะขอยกตัวอย่างแค่การใช้ decorator กับฟังก์ชั่นธรรมดาง่ายๆ นะครับให้พอเห็นภาพ

สมมุติว่าเรามีฟังก์ชั่น fizzbuzz ตามนี้

def fizzbuzz(number):
    if number % 3 == 0 and number % 5 == 0:
        return 'fizzbuzz'
    elif number % 3 == 0:
        return 'fizz'
    elif number % 5 == 0:
        return 'buzz'
    else:
        return number

แล้วเราอยากจะให้แสดงผลออกมาแบบมีข้อความขึ้นสักหน่อยเช่น Your input is 3, so you get fizz. ถ้าเราสะดวกเราก็เข้าไปแก้ฟังก์ชั่นของเราเลยใช่ไหมครับ เราก็จะได้ฟังก์ชั่นหน้าตาแบบนี้

def fizzbuzz(number):
    result = 'Your input is ' + str(number) + ', so you get '
    if number % 3 == 0 and number % 5 == 0:
        result += 'fizzbuzz'
    elif number % 3 == 0:
        result += 'fizz'
    elif number % 5 == 0:
        result += 'buzz'
    else:
        result += str(number)
    return result + '.'

ดูแล้วไม่ค่อยน่าทำเลยใช่ไหมครับ? เรามาลองใช้ decorator กันดีกว่า ให้เราสร้าง nested function หรือ inner function  ขึ้นมาตามนี้ (ที่ต้องทำตามนี้เพราะว่านี่เป็น syntax ของ Python decorator ครับ)

def have_nice_message(func):
    def wrap(number):
        result = 'Your input is ' + str(number) + ', so you get '
        result += func(number)
        result += '.'
        return result
    return wrap

วิธีใช้งานเราก็แค่เอาไปแปะไว้บนหัวของฟังก์ชั่นที่เราต้องการตามนี้

@have_nice_message
def fizzbuzz(number):
    if number % 3 == 0 and number % 5 == 0:
        return 'fizzbuzz'
    elif number % 3 == 0:
        return 'fizz'
    elif number % 5 == 0:
        return 'buzz'
    else:
        return number

ผลลัพธ์ที่ได้ก็จะเหมือนกันโค้ดที่เราเข้าไปเพิ่มข้อความ แต่โค้ดที่เราได้มาจะดูสะอาดตามากขึ้น ฟังก์ชั่นเราก็ยังคงทำหน้าที่เหมือนเดิมตามปกติ 🙂

วิธีแก้ปัญหา buildbot create-master master แล้วเจอ ImportError

ถ้าเวลารันคำสั่ง buildbot create-master master แล้วเจอ error 3 บรรทัดสุดท้ายเป็นประมาณนี้

  File "/home/zkan/.virtualenvs/ci/local/lib/python2.7/site-packages/migrate/versioning/schema.py", line 10, in <module>
    from sqlalchemy import exceptions as sa_exceptions
ImportError: cannot import name exceptions

ให้ไปหาไฟล์  schema.py ที่ขึ้น error นั้น (ลองดู path จาก error บนเครื่องตัวเองเอานะครับ เพราะแต่ละเครื่องคงจะไม่เหมือนกัน) แล้วให้เปลี่ยนบรรทัดด้านล่างนี้

from sqlalchemy import exceptions as sa_exceptions

เป็น

try:
    from sqlalchemy import exceptions as sa_exceptions
except ImportError:
    from sqlalchemy import exc as sa_exceptions

ใส่คำสั่ง try-catch ไว้นั่นเอง เพื่อให้มัน import ตัวโมดูล exc มาแทน ถ้าไม่มี exceptions พอเสร็จแล้วก็ลองรันคำสั่งสร้าง master ใหม่อีกรอบดู น่าจะรันได้แล้ว

รู้สึกเหมือนกับว่าเวอร์ชั่นของ SQLAlchemy มันไม่ compatible กับ Buildbot เวอร์ชั่น ณ ตอนนี้เลยทำให้เกิดปัญหา

ด้านล่างนี้เป็น environment ที่ผมลง Buildbot (เวอร์ชั่น 0.8.7p1) ไว้ ทำตามวิธี Installation นี้

(ci)zkan@vgl:~$ pip freeze
Jinja2==2.7
MarkupSafe==0.18
SQLAlchemy==0.8.2
Tempita==0.5.1
Twisted==13.1.0
argparse==1.2.1
buildbot==0.8.7p1
decorator==3.4.0
python-dateutil==1.5
sqlalchemy-migrate==0.7.2
wsgiref==0.1.2
zope.interface==4.0.5

My GSoC 2012 Proposal

This is my first attempt at Google Summer of Code (GSoC) 2012. I will propose my project idea to SimpleCV. I think it would be useful if I share my proposal here whether it will be accepted or rejected. 🙂 Anyway, you can find it [here].

Below is the quote from Anthony (one of the developers for SimpleCV) in pythonvision at googlegroups dot com. I would like to post it here, so readers can get the idea what SimpleCV is.

SimpleCV wrappers OpenCV amongst others. If you are new to computer vision it is probably worth a look as we have a bunch of examples: http://examples.simplecv.org

To be honest, that's how the whole SimpleCV project started. We got sick of their not being documentation, and were using other tools like ipython, etc, that we wanted integrated.  We have also written our own blob detection library because we got sick of compile errors and having to use cvblob as a dependency.

We have a long way to go, and for seasoned vision programmers SimpleCV is probably not the route you want to go, if you are beginner it's definitely easier to get up and running.  I wrote an article about the differences recently and I welcome any feedback: http://simplecv.tumblr.com/post/19307835766/opencv-vs-matlab-vs-simplecv

I think people get the misconception we are trying to replace opencv, and by no means is the case. We label ourselves as a framework not as a library.  Think of us as a jquery or rails (ruby on rails) for vision. 🙂

Simple Linear Regression in Python

Linear regression เป็นการโมเดลข้อมูลโดยใช้ความสัมพันธ์เชิงเส้นที่มีตัวแปรตาม 1 ตัว และตัวแปรอิสระตั้งแต่ 1 ตัวขึ้นไป สิ่งที่เราจะต้องทำคือหาสมการเชิงเส้นที่เหมาะสมกับข้อมูลนั้นๆ ในบล็อกนี้จะกล่าวถึงแค่ simple linear regression ซึ่ง จะมีตัวแปรอิสระแค่ 1 ตัว แล้วเราจะได้สมการเชิงเส้นดังนี้

y = a + bx

โดย y คือตัวแปรตาม (dependent variable) ส่วน x คือตัวแปรอิสระ (independent variable) ค่าสัมประสิทธิ์ (coefficient) a คือค่าของ y ตอนที่ x มีค่าเป็น 0 ดังนั้นเราสามารถเรียกได้ว่าเป็นจุดตัดแกน y หรือ y intercept นั่นเอง ส่วนค่าสัมประสิทธิ์ b คือความชัน (slope) ของเส้นตรงนั่น หรือค่าที่เปลี่ยนแปลงไปของ y เมื่อมีการเปลี่ยนแปลงที่ x ดูรูปข้างล่างนี้ประกอบ

สำหรับใครที่สนใจอยากรู้ว่าคำนวณอย่างไร ก็แนะนำให้อ่านการสอนของ Stefan Waner และการสอนของ Stephen Mak เพราะผมอ่านแล้วเข้าใจกว่าอ่านใน Wiki แหละ 😛

เอาล่ะ ไม่ต้องเขียนให้มากความ จัดโค้ดไปเลยดีกว่า ดาวน์โหลดได้ที่นี่ [Simple Linear Regression in Python] ข้างในจะประกอบไปด้วย 2 ไฟล์ดังนี้

  1. ไฟล์หลัก: main.py
  2. ไฟล์คลาส LinearRegression: linreg.py

โดยโปรแกรมจะคำนวณค่า a, b, coefficient of determination, coefficient of correlation, standard error of estimate, และ mean squared error of estimate ออกมาให้ครับ

โปรแกรมนี้เป็นโปรแกรมเกือบจะโปรแกรมแรกเลยที่เขียนด้วย Python เองเต็มๆ แบบว่าอยากทำงานและก็อยากศึกษาภาษาใหม่ไปด้วยในตัวก็เลยลองดู 🙂 เนื่องจากปกติเขียนแต่ภาษา C/C++ หรือ Java พอมาเขียน Python ก็เลยต้องเขียนไปบ่นไป ฮะๆ คิดว่าถ้าลองเขียนไปอีกสักพักน่าจะปรับตัวได้ แล้วก็ฝีมือในการเขียน Python ก็ยังอ่อนด้อยอยู่มาก ถ้าใครมีอะไรเพิ่มเติม ดุ ด่า เกี่ยวกับโค้ดก็ยินดีเลยครับ หรือจะเอาไปพัฒนาต่อก็ไม่ว่ากัน

ปล. โค้ดในบล็อกนี้แปลงมาจากโค้ด C++ ของ David C. Swaim II เกือบทั้งดุ้นเลยนะครับ หุหุ