2012

2012年10月24日 星期三

Using Borg to instead of singleton in Python


上篇有說到可以使用singleton方式,當多個物件同時對一個資源做修改時,不會造成race condition,這篇將繼續介紹另一種更方便的方式 Borg



def borg(cls):
    cls._state = {}
    orig_init = cls.__init__
    def new_init(self, *args, **kwargs):
        self.__dict__ = cls._state
        orig_init(self, *args, **kwargs)
    cls.__init__ = new_init
    return cls

class animal(object):
    def __init__(self,name):
        self.name = name

    def assign_count(self):
        self.count = 0

    def pringInfo(self):
        self.count = self.count + 1
        print "%s appear %s times"%(self.name,self.count)

animal = borg(animal)

if __name__ == '__main__':
    b1 = animal("dog")
    b1.assign_count()
    b1.pringInfo()
    b2 = animal("cat")
    b2.pringInfo()


執行結果:

root@ubuntu:/mnt/test# python borg.py
dog appear 1 times
cat appear 2 times
cat appear 3 times




2012年10月23日 星期二

Singleton in Python


運用Singleton可以讓物件同時間只會產生一份,這樣就可以避免共用資源的race condition發生。



def singleton(cls):
    instances = {}

    def getinstance(*args, **kwds):
        return instances.setdefault(cls, cls(*args, **kwds))

    return getinstance

class Foo(object):
    def __init__(self, attr=1):
        self.attr = attr
        self.counter = 0

    def add_count(self):
        self.counter = self.counter + 1

Foo = singleton( Foo )

if __name__ == "__main__":
    ins1 = Foo(2)
    ins1.add_count()
    print "Foo(2) -> id(ins)=%d, ins.attr=%d,%s" % (id(ins1), ins1.attr, ('error','ok')[ins1.attr==2])
    print "Foo(2) counter: %d" %ins1.counter
    ins2 = Foo(3)
    ins2.add_count()
    print "Foo(3) -> id(ins)=%d, ins.attr=%d,%s" % (id(ins2), ins2.attr, ('error','ok')[ins2.attr==2])
    print "Foo(3) counter: %d" %ins2.counter
    ins2.attr = 5
    print "ins.attr=5 -> ins.attr=%d, %s" %(ins2.attr,('error','ok')[ins2.attr==5])



執行結果:
root@ubuntu:/mnt/test# python singleton.py
Foo(2) -> id(ins)=140287766113104, ins.attr=2,ok
Foo(2) counter: 1
Foo(3) -> id(ins)=140287766113104, ins.attr=2,ok
Foo(3) counter: 2
ins.attr=5 -> ins.attr=5, ok

2012年10月21日 星期日

Monkey Patching in Python


這陣子接了一個專案

而上層又提出要增加unitest的功能

但是如果依照舊程式碼要來改的話

就會改到天荒地老

所以這邊使用了一個小撇步 Monkey Patching

透過這個方式就可以把import的Module用自己的module給替換掉

非常方便

main.py
#!/usr/bin/env python
import sys


if __name__ == '__main__':
        import os
        from test import os as fake_os
        old = os
        sys.modules['os'] = fake_os

        import os
        os.system("touch a")

        sys.modules['os'] = old



os.py
#!/usr/bin/env python

def system(cmd):
        print cmd


Refactoring in Python


接觸了一陣子的Python

開始想要讓自己的程式碼能更有彈性化與更好Debug

所以在網路上搜尋了一下 Design Pattern for Python

真的有一堆東西

其中剛好有人寫到 Refactoring Python

就開始著手修改自己的Coding Style

底下會先用一個列出 動物有幾隻腳 的程式做為範例

在拿Refactoring後的程式與一開始常寫的東西做對比


重構前:
#!/usr/bin/env python

def animal_info(animal_type):
        feet = 0
        if animal_type == "lion":
                feet=4
        elif animal_type == "duck":
                feet=2
        elif animal_type == "dog":
                feet=4
        print "%s has %s feet"%(animal_type,feet)


if __name__ == "__main__":

        animal_info("lion")
        animal_info("duck")
        animal_info("dog")



重構後:
#!/usr/bin/env python

def animal_inspect(animal_type):
        animal_dict = {
        "dog" : { "feet":"4"},
        "duck" : { "feet":"2"},
        "lion" : { "feet":"4"}
        }

        animal_info = animal_dict[animal_type]
        animal_feet = animal_info["feet"]
        print "%s has %s feet"%(animal_type,animal_feet)

def main():
        animal_array = ["lion","duck","dog"]
        for animal_type in animal_array:
                animal_inspect(animal_type)


if __name__ == "__main__":
        main()



雖然重構後的架構會稍微的複雜些

但是如果要修改或是擴增上 就會便利許多

尤其是if else當越寫越長

就會越來越難debug

透過dict方式來替代if else的確是很棒的方式

2012年6月6日 星期三

Ubuntu12.04 讓區域網路透過無線網路連線


人手一支高階智慧型手機已是常態,但怎麼讓綁約吃到飽的無線網路能善盡其用,就是我想研究的主題之一。剛好公司鎖東鎖西的網路已造成我某種程度的不便,就趁此機會利用無線網路來跳出萬惡的公司防火牆吧。

此次是透過智慧型手機的usb網路共享來實現,底下會一一的透過設定圖來解釋。

在網路設定裡面,我們會先建立兩個連線,一個是shared to Lan,一個是wifi。


由下圖知道wifi就是透過USB連結到手機的無線網路分享


在wifi的網路設定中是透過Automatic(DHCP)方式去指定ip等設定。


由下圖知shared to Lan是使用有線網卡,並連結到ip分享器,


在ipv4的setting中採用shared to another computers的方式,讓所有電腦能透過這張網卡去使用USB無線網路


下圖是完成後的網路設定值



其他電腦只需連結到ip分享器,並且使用自動取得ip的方式,就可以順利透過無線網路上網。

後記:
一開始我是想說用notebook的無線網卡直接分享網路,但是win7的設定太過繁複,問題太多無法順利解決,最後改變做法去解,但之後有空會再研究更方便的方式。XD

2012年3月7日 星期三

Socket in Python


之前就稍微學過c的socket program, 最近剛好再接觸python,也就順道一起研究
這次會介紹透過ip互相溝通與process間互相溝通的兩種寫法(寫法幾乎相同 只差在參數的調用部分)


1.透過ip互相溝通:

Server code:

#!/usr/bin/python
import socket,os


HOST = ''                 
PORT = 5566              


if __name__ == '__main__':
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) #註1
        s.bind((HOST, PORT)) #註2
        s.listen(5) #註3
        while(1):
                conn, addr = s.accept() #註4
                print 'Connected by', addr
                try:
                        conn.settimeout(10) #註5
                        data = conn.recv(1024) #註6
                        if not data:
                                print 'Error'
                                conn.send('Error')
                        elif data =='exit':
                                conn.send('bye')
                                break
                        else:
                                print "======start====="
                                os.system(data)
                                conn.send('Executed '+data) #註7
                except socket.timeout:
                        print 'time out'
                conn.close()

註1:AF_INET表示使用internet來進行傳輸,SOCK_STREAM表示使用TCP協定
註2:將socket綁定到指定的HOST和PORT
註3:設定server的隊列大小
註4:等待client連接
註5:設定timeout時間為10秒
註6:接收command的最大size為1024byte
註7:送字串傳去client

Client code:

#!/usr/bin/python


import socket,sys


if __name__ == '__main__':


        if len(sys.argv) < 3:
                print 'please check the insertion'
        elif sys.argv[2].strip() == '':
                print 'please check the command'
        else:
                HOST = sys.argv[1]    
                PORT = 5566          

   
                s = socket.socket(socket.AF_INET,

socket.SOCK_STREAM)
                s.connect((HOST, PORT))
                s.sendall(sys.argv[2])
                data = s.recv(1024)
                s.close()
                print 'Received', repr(data)


send和sendall 的差別:
send: 最後會回傳總共傳送了多少byte,如果只有一些字元被傳送,application會繼續負責把剩餘的資料傳完。
sendall: 這個函數會負責把文字傳送到另一端,但如果沒傳送完全會跳excepcttion,且沒辦法知道總共傳送了多少字元,回傳0

是代表傳送成功。



2.process間互相溝通:

Server code:

#!/usr/bin/python
import socket,os,sys


if __name__ == '__main__':
        sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) #註8
        if os.path.exists('/mnt/pc.d'): #註9
                os.unlink('/mnt/pc.d')
        sock.bind('/mnt/pc.d')
        sock.listen(5)
        while True:
                conn, addr = sock.accept()
                data = conn.recv(1024)
                os.system(data)
                conn.send('Execute '+data)
                conn.close()


Client code:

#!/usr/bin/python
import socket,time,sys


if __name__ == '__main__':
        sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
        sock.connect("/mnt/pc.d")
        sock.send(sys.argv[1])
        print sock.recv(1024)
        sock.close()


#註8: AF_UNIX 是用於同一台電腦中process與process互相溝通時所調用的參數
#註9: 這邊會把HOST和PORT轉換成指定到電腦上的某一個檔案 所以要保證此檔案不存在 不然會發生錯誤


總結:
python程式比起c來說真的是好寫太多,c要用近百行的程式碼來寫socket,而python只需十幾行,真的很簡單,但是python是沒有multi-thread的,所以在loading重的情況下,容易造成lag,要改成multi-process。