วันพฤหัสบดีที่ 28 พฤษภาคม พ.ศ. 2552

Python direct function by string

สักวันหนึ่งเราคงได้พบว่า การเขียน if else เพื่อเลือกเรียก function นั้น เป็นเรื่องรกและสิ้นเปลืองพลังงาน แถมยังทำให้ code ไม่สวยงาม
ในส่วนของ post ชุดนี้จึงนำเสนอวิธีการเรียก function ด้วย string มาแต่จำเป็นที่ string นั้น จะต้องเป็นชื่อเดียวกับ function นะครับ โดยตัวอย่างนี้มีอยู่สองวิธีครับ ตามด้านล่างเลย

สมมุติ code มีอยู่ว่า

class Test(object):
    def __init__(self):
        pass
    def a(self, data):
        print '--a-- %s' %str(data)

    def b(self, data):
        print '--b-- %s' %str(data)

    def c(self, data):
        print '--c-- %s' %str(data)

    def call(self, fname, data):
        if 'a' == fname:
            self.a(data)
        elif 'b' == fname:
            self.b(data)
        else:
            self.c(data)

1. การใช้ eval() << เหมาะกับการใช้เรียกแบบตรง ๆ ซึ่งไม่จำเป็นว่า function ที่เรียกต้องอยู่ใน Object

def call(fname, data):
try:
eval('self.%s(data)' %fname)
except:
self.c(data) #default call function c

2. การใช้ getattr() << สะดวกมาก แต่ใช้ได้แต่กับ object เพราะต้องอ้าง attribute

def call(fname, data):
getattr(self, fname, 'c')(data)

และในกรณีใด ๆ ที่เราต้องการอ้างถึง object ตัวอื่น ก็สามารถแทนที่ของ self ครับ ไม่จำเป็นว่าต้องเรียกตัวเองเสมอไป

ค่อยข้างจะมีประโยชน์คนละแบบครับ แล้วแต่การใช้งาน

วันอังคารที่ 26 พฤษภาคม พ.ศ. 2552

Lighttpd change http port and path url

Lighttpd เป็น tool ตัวหนึ่งในการช่วยจัดการกับ การเข้าถึง web, directory, load balance, block path
ดู ๆ ข้างในแล้ว เหมือนจะทำขึ้นเพื่อ php มากเลย -.-"
(เอาเป็นว่ารายละเอียดไว้ทีหลัง การติดตั้งหรืออะไรต่าง ๆ หรือไปอ่านเองก่องเถอะครับ เหอ ๆ ว่าง ๆ คงได้เอามาลงครับ)

ตอนนี้จะเป็นการ เปลี่ยน path url การเข้าถึง และ เปลี่ยน port url พร้อม ๆ กัน
(สถาณการณ์บีบบังคับ ทำให้งานออกมาได้จิง ๆ ไม่ต้องรอ บริ้วววว อารมณ์)

งานคือ url ที่ client เรียกเข้าถึงเป็น

http://www.vserver.com/gw/mo/oper1

server ตั้งอยู่ที่ (url จริง ในการใช้งาน)

http://www.vserver.com:8081/req/oper1

ในส่วนของ oper นั้น จะมี oper1, oper2, oper3 ครับ

ขึ้นตอนแรก เข้าไปหา file ชื่อว่า

/etc/lighttpd/lighttpd.conf

เผอิญว่า ทางพี่ ๆ เค้าลงไว้บน ubuntu ให้เสร็จแล้ว ไม่แน่ใจนะครับว่าอยู่ pathนี้ตลอดเปล่า

ขึ้นที่สอง ก็ไปเพิ่ม หรือเอา comment ออกครับในส่วนของ
(comment คือ เครื่องหมาย # หน้าบรรทัด หรือ ข้อความ)

server.modules = (
   "mod_xxxxxxxx", # << 'xxxxxxxx' อันนี้ละไว้ว่าอันอื่น ๆ ครับ
#   "mod_xxxxxxxx", # << แบบนี้คือ comment
   "mod_rewrite",
   "mod_redirect",
   "mod_proxy"
)


ขั้นที่ 3 นั้น แบ่งเป็น 2 ส่วนครับ
3.1 ใช้แบบ redirect
กรณีนี้จะสั้นครับเหมาะกับการเข้าถึง หรือ ใช้ http method get ครับ

#-----------------------------------
$HTTP["host"] == "www.vserver.com" {
  url.redirect = ("^/gw/mo/(.+)" => "http://www.vserver.com:8081/req/$1")
}
#-----------------------------------


$HTTP["host"] == "www.vserver.com" { # << เป็นเหมือนคำสั่งใช้ในการ if คือ ถ้า url เป็นชื่อนี้ก็จำเข้ามาทำงาน

(.+) # << เป็นการแทนค่า path url และ parameter ที่ต่อท้าย เพื่อนำมาแทนใน $1 และสามารถกำหนดได้มากกว่า 1 ตัว เช่น ข้อมูลมาในแบบ rest คือ /gw/mo/(.*)/(.*)/(.*) => /gw/mo/$1?id=$2&price=$3 เป็นการแปลงเป็น name value ธรรมดาครับ

3.2 ใช้แบบ rewrite
กรณีนี้จะต้องทำสองอย่างครับ คือ เปลี่ยน path url ก่อน แล้วค่อย proxy ยัง post ที่ต้องการครับ เนื่องจาก 3.1 นั้นใช้ได้แต่เฉพาะ http method get ถ้าจะใช้ http method post ก็คงเขียนยาวหน่อยครับ

#-----------------------------------
$HTTP["host"] == "www.vserver.com" {
  url.rewrite-once = ("^/gw/mo/(.*)$" => "/req/$1")
  $HTTP["url"] =~ "^/req" {
    proxy.server = (
      "" => (
        "vserver" => (
        "host" => "127.0.0.1",
        "port" => 8081,
        "fix-redirects" => 1
        )
      )
    )
  }
}
#-----------------------------------


เสร็จแล้วก็ทำการ restart ด้วยคำสั่ง

#-----------------------------------
$ /etc/init.d/lighttpd restart
#-----------------------------------


ก็เป็นอันเรียบร้อยครับ
อ๋อ ในกรณี post data xml
syntax จะ ประมาณนี้
<xml> <data> data 123 abc... </data> </xml>

เมื่อทำการ post ให้ใส่ content type : text/xml ด้วยครับ
ไม่ใช่นั้น ปีกกว่าจะเปลี่ยนไป จะได้ประมาณนี้ครับ
%3Cxml%3E %3Cdata%3E data 123 abc... %3C2Fdata%3E %3C%2Fxml%3E

จบแต่เพียงเท่านี้ -.-" กว่าจะหาเจอ ตอนแรกไม่รู้ว่ารวมเป็น combo ได้

วันพุธที่ 13 พฤษภาคม พ.ศ. 2552

python yield

เห็นแว๊บ ๆ สำหรับ keyword 'yield' สำหรับ python ก็มานั่งดูว่าใช้ประโยชน์อะไรได้บ้าง พอดีเห็นตัวอย่างง่าย ๆ เอามาทำความเข้าใจ เหมือนกับว่า มันจะใช้ช่วยในการ return ข้อมูลออกมา จาก function ที่กำลังดำเนินการาอยู่ ดูตัวอย่างดีกว่า

def odds(limit):
    i = 1
    while True:
        if limit > i
            break
        print 'in odds : > %s' % str(i)
        yield i
        i += 2

for i in odds(5):
    print 'odds : %s' % str(i)

## return
in odds : > 1
odds : 1
in odds : > 3
odds : 3
in odds : > 5
odds : 5


function ดึงแต่เลขคี่ ที่ค่าไม่เกิน limit
จากที่เห็น ก็จะเห็นว่า จะมีการเรียกเข้า function odds ซึ่งยังทำการเทียบข้อมูลไม่ถึง limit ที่ตั้งไว้ก็จะมีการ return ค่าออกมาให้ function เรียกใช้งานทำงานไปก่อน

ซึ่งจะต่างจาก function ธรรมดาทั่วไป ที่ทำการ return function เมื่อทำงานเสร็จสิ้น ตามตัวอย่างนี้

def odd2(limit):
    r = []
    i = 1
    while 1:
        if i > limit:
            break
        print 'in odd2 : > %s' % str(i)
        r.append(i)
        i += 2
        return r

for i in odd2(5):
    print 'odd2 : %s' % str(i)

## return
in odd2 : > 1
in odd2 : > 3
in odd2 : > 5
odd2 : 1
odd2 : 3
odd2 : 5


โดย ดู ๆ แล้ว ในส่วนของ yield น่าจะใช้กับ function loop ที่ต้องการทำงานกับ ตัวแปร ภายนอก ที่มีการเปลี่ยนแลงเรื่อย ๆ


มาเพิ่มตัวอย่างอีกสักสองอันครับ สำหรับ สุดยอด function นี้
อันแรกเป็นการเขียนเพื่อจับคู่ loop แต่ละ list ครับ
def for_2list(l1, l2):
    for i1 in l1:
        for i2 in l2:
            yield i1, i2
เวลาเรียกใช้
ll1 = ['a', 'b', 'c']
ll2 = [1, 2, 3]

for a1, a2 in for_2list(ll1, ll2):
    print ' >> %s, %s' %(a1, a2)

ผลลัพท์
>> a, 1
>> a, 2
>> a, 3
>> b, 1
>> b, 2
>> b, 3
>> c, 1
>> c, 2
>> c, 3

มาเพิ่มเติมกันอีกสักอันครับ สำหรับตัวอย่าง แจ่ม ๆ ที่น่าจะได้ใช้กันบ่อย
คือ loop list ทีละ pack โดยกำหนด pack ได้เองว่าทีละเท่าไร

def for_list_pack(list, size):
    i=0;j=size
    while(True):
        if j > len(list):
            j = len(list)
        data = list[i:j]
        yield data
        if j == len(list):
            break
        i=j;j=i+size

เวลาเรียกใช้
l1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]

for p in for_list_pack(l1, 3):
    print ' >> %s ' %p

ผลลัพท์

>> [1, 2, 3]
>> [4, 5, 6]
>> [7, 8, 9]
>> [0]


จริง ๆ เอาไปใช้งานได้เลยแหละครับ ^_^

วันจันทร์ที่ 11 พฤษภาคม พ.ศ. 2552

วันศุกร์ที่ 8 พฤษภาคม พ.ศ. 2552

python cut string by count to list

ตัวอย่างเล็ก ๆ เกี่ยวกับการ ตัดข้อความทีละจำนวนตัวอักษรที่เรากำหนด
m = 'abcdefghijklmnopqrstuvwxyz0123456789'
x = '10'

l = [m[i:i+x] for i in range(0, len(m), x)]
print l

result
['abcdefghij', 'klmnopqrst', 'uvwxyz0123', '456789']

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

หวังว่าคงมีประโยชน์บ้างน่อ ^_^

วันพฤหัสบดีที่ 7 พฤษภาคม พ.ศ. 2552

python check message is thai language

code แบบง่าย ๆ เอาไปใช้ก่อน
#function long

def isthaistr(s):
    for i in s:
        if 255 < ord(i):
            return True
    return False
#function short

def isthaistr(s):
    return any( ord( c ) > 255 for c in s ) 
ในกรณีที่ข้อความเราได้มานั้น เป็น TIS-620 เราอาจต้องแปลงเป็น UTF-8 โดย encode มันด้วยสำสั่งแบบนี้
s = 'ก'
print ord(s) # 161
s = s.decode('its-620')
pirnt ord(s) # 3585

s = 'a'
print ord(s) # 97
s = s.decode('tis-620')
print ord(s) # 97
ประมาณนี้...

python multi decorator

เนื่องจากเมื่อครั้งก่อนหน้านี้ ได้สร้าง decorator ในหัวข้อ python decorator แล้วบังเอิญว่า ไม่ได้ใช้ พอมาจับอีกทีถึงรู้ว่า คราวที่แล้ว ที่กำหนด decorator เป็น class นั้น มัีนค่อยข้างบีบความสามารถ ไว้ถ้าว่าง ๆ คงไปนั่งแก้และหาวิธีแก้ไขเพิม เนื่องเติมจาก ช่วงนี้ มีการเขียน code ที่ต้องเกี่ยวข้องกับระบบอื่น ๆ มากมาย หรือเรียกว่า ในส่วนที่ทำเป็น adaptor ก็ถูก

เอาเป็นว่าเข้าเรื่องดีกว่า ไม่รู้โม้ทำไม

เรื่องมีอยู่ว่า เนื่องจากในส่วนของ decorator ของ python นั้น มันค่อนข้างจะนำมาประยุกต์ใช้งาน ทำให้ code ที่ต้องเขียนซ้ำ ๆ กันน้อยลง นั่นคือ การใช้ @(decorator) ในการครอบ function บาง function โดยไม่ต้องเขียนให้เห็น ๆ กะตา

แต่ ถ้าเราต้องการมากกว่านี้หละ ครอบหลาย ๆ ชั้น เมื่อครั้งที่แล้วใช้ class ไป จึงรู้ว่า ในส่วนของ decorator นั้น เวลาทำงานมันจะเรียก function ที่อยู่ถัดจากมัน ดังนั้น ถ้าเกิดเราเขียน decorator เป็น class หละก็ เท่ากับว่า เรากำลังปิดทางทำมาหากินเราในอนาตนต่อไป ในหัวข้อนี้จึงเป็นการแนะำนำการเขียน decorator เป็น function เพื่อ ทำการ ซ้อน function เข้าไป เยอ ๆ สนุกดี

เริ่มเลย ...

decorator แรกนี้เป็นในส่วนทำการแสดงผล หลังจากทำงานเสร็จ เพื่อให้อยู่ใน format
def get_result(f):
    def wrap_func(*arg, **kw):
        try:
            f(*arg, **kw)
            return {'status_code':'200', 'status_description':'Success'}
        except Exception, e:
            return {'status_code':'500', 'status_description':str(e)}
    return wrap_func
ส่วนที่สอง เป็นในส่วน check parameter
def req_param(*fields):
    def req_paramn(f):
        def wrap_func(*arg, **kw):
            for field in fields:
                if not kw.has_key(field) or '' == kw.get(field).strip():
                    raise Exception('parameter %s not empty.' % field)
            return f(*arg, **kw)
        return wrap_func
    return req_paramn
ส่วนสุดท้าย function ที่ทำงาน
@sendcont_result
@req_param('ntype', 'to', 'from', 'message')
def on_call(**kw):
    try:
        if 'DTAC' == kw.get('ntype'):
            on_dtac(**kw)
        elif 'AIS' == kw.get('ntype'):
            on_ais(**kw)
        else:
            raise Exception('not support ntype %s.' % str(kw.get('ntype')))
        return kw
    except Exception, e:
        raise e
เวลาเรียกใช้ก็
res = on_call({'ntype':'AIS', 'message':'hi python.', 'to':'you', 'from','i'})
ผลลัพท์ 'res' ถ้าไม่เกิด error เราก็จะเป็น
status_code = 200
นอกนั้น ก็
status_code = 500

เช่น ในกรณีที่เราไม่ได้ใส่ ntype เข้ามา ก็จะฟ้องว่า
status_code = 500
status_description = parameter ntype not empty.
หรือ กรณี method on_dtac หรือ on_ais มีปัญหา ก็จะแสดงคล้ายข้างบนครับ

ตัวอย่างเท่านี้ ที่เหลือก็ขึ้นอยู่กับการประยุกต์ครับ