<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:creativeCommons="http://backend.userland.com/creativeCommonsRssModule" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0"><channel><atom:id>tag:blogger.com,1999:blog-5817647334262996203</atom:id><lastBuildDate>Fri, 13 Jan 2012 19:26:37 +0000</lastBuildDate><category>Python</category><category>Lex</category><category>JSP</category><category>CSS</category><category>C/C++</category><category>軟體</category><category>本站</category><category>TinyMCE</category><category>emomeDDSMS</category><category>Skype API</category><category>FreeBSD</category><category>xslt</category><category>Perl</category><category>Code::Blocks</category><category>程式設計</category><category>Java</category><category>Google App Engine</category><category>Netlimit IP Switcher</category><category>電子書</category><category>wxPython</category><category>MySQL++</category><category>PHP</category><category>Timer</category><category>SudokuBoxer</category><category>MFC</category><category>Linux</category><category>Delphi</category><category>Chickenfoot</category><category>BCB</category><category>Win32</category><category>Ubuntu</category><category>Lifetype</category><category>wxWidgets</category><title>Falldog的程式戰場</title><description /><link>http://falldog7.blogspot.com/</link><managingEditor>noreply@blogger.com (Falldog)</managingEditor><generator>Blogger</generator><openSearch:totalResults>106</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/Falldog" /><feedburner:info uri="falldog" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><creativeCommons:license>http://creativecommons.org/licenses/by-sa/2.5/</creativeCommons:license><image><link>http://creativecommons.org/licenses/by-sa/2.5/</link><url>http://creativecommons.org/images/public/somerights20.gif</url><title>Some Rights Reserved</title></image><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5817647334262996203.post-1183314457049451615</guid><pubDate>Thu, 04 Aug 2011 02:53:00 +0000</pubDate><atom:updated>2011-08-04T10:54:48.624+08:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Python</category><title>[Python] Lazy initialization</title><description>在寫大型的Project時，應該都會遇到一種痛，就是AP開起來的速度"操級慢"，很多人習慣在一開始就把一些用不到的變數initial起來，不但影響到AP launch的速度，也會讓memory吃得肥茲茲的。&lt;br /&gt;
&lt;br /&gt;
所以就有人嘗試在一開始將變數initial成None，等到要用時再判斷是不是None，是的話再真正的initial這個變數。&lt;br /&gt;
&lt;br /&gt;
不過這種作法，可能會讓code變得稍微複雜一點，參考一下別人的作法，其實有更好的方法來實作這種Lazy Initialization，就是用到Python的decorator+property！&lt;br /&gt;
&lt;br /&gt;
&lt;a name='more'&gt;&lt;/a&gt;&lt;span class="Apple-style-span" style="font-family: monospace; white-space: pre;"&gt;&lt;/span&gt;&lt;br /&gt;
&lt;pre class="prettyprint"&gt;def lazyproperty(func):
    ''' 
    Lazy initialization - Design Pattern
    Implement it by property
    
    Usage - 
        class Foo(object):
            def __init__(self):
                super(Object,self).__init__()
            @lazyproperty
            def sum(self):
                _sum = 0
                for i in range(100):
                    _sum += i
                return _sum
        o = Foo()
        print o.sum
    
    Information -
        the setter raise exception only if the class inhert from object!
    '''
    attr = '_lazy'.join( func.__name__ )
    def get_lazyval(self):
        if not hasattr(self, attr):
            setattr(self, attr, func(self))
        return getattr(self, attr)
    def set_lazyval(self, v):
        raise AttributeError('The lazy property is read-only')
    return property(get_lazyval, set_lazyval)
&lt;/pre&gt;透過這個方式，等到get這個instance的變數時，才會執行init function裡的事，只是，如果希望set有exception的話，必須要讓class繼承object才有基本property的功能。&lt;br /&gt;
&lt;br /&gt;
Reference :&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;StackOverflow - &lt;a href="http://stackoverflow.com/questions/3012421/python-lazy-property-decorator/3013910#3013910"&gt;Python lazy property decorator&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Design Pattern - &lt;a href="http://en.wikipedia.org/wiki/Lazy_initialization"&gt;Wiki - Lazy initialization&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5817647334262996203-1183314457049451615?l=falldog7.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://feedproxy.google.com/~r/Falldog/~3/jZ5lAqR4EkU/python-lazy-initialization.html</link><author>noreply@blogger.com (Falldog)</author><thr:total>0</thr:total><feedburner:origLink>http://falldog7.blogspot.com/2011/08/python-lazy-initialization.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5817647334262996203.post-4508536711214491578</guid><pubDate>Tue, 12 Apr 2011 02:13:00 +0000</pubDate><atom:updated>2011-04-12T10:34:08.126+08:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Python</category><title>[Python] 取得Python object的reference count</title><description>在Python的世界裡，每個變數都是一個object，而且每個object會有一個reference count去記錄被reference幾次，一但這個值變0時，這個object才會真正被delete掉。&lt;br /&gt;
&lt;br /&gt;
&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
在Python的sys module裡，提供了一個API &lt;a href="http://docs.python.org/library/sys.html#sys.getrefcount"&gt;getrefcount&lt;/a&gt;()可以取得一個object的reference count是多少，回傳值是數字，而且回傳值應該會比你預期的值還要高，這是因為object在傳進getreference()時，reference count就會偷偷加一了。&lt;br /&gt;
&lt;br /&gt;
看到下面的範例，a是一個Test的instance，reference count跟預期一樣是2(一個link到a，一個link到getrefcount的temporarily的變數)，而b是一個list的instance，結果跟a一樣。&lt;br /&gt;
&lt;br /&gt;
不過c跟d是一個string object，Python底層將c跟d link到同一個instance，所以在d='a'之後，c的reference count再加1。不過數字為何這麼地高，猜測應該是Python底層有自己去cache這些string object吧。&lt;br /&gt;
&lt;pre class="prettyprint"&gt;import sys

class Test:
    def __init__(self, v):
        self.v = v
a = Test(0)
print id(a), sys.getrefcount(a)
#&amp;gt;&amp;gt;&amp;gt; 19119440 2

b = list()
print id(b), sys.getrefcount(b)
#&amp;gt;&amp;gt;&amp;gt; 19135064 2

c = 'a'
print id(c), sys.getrefcount(c)
#&amp;gt;&amp;gt;&amp;gt; 18765728 18
d = 'a'
print id(c), sys.getrefcount(c)
#&amp;gt;&amp;gt;&amp;gt; 18765728 19
print id(d), sys.getrefcount(d)
#&amp;gt;&amp;gt;&amp;gt; 18765728 19&lt;/pre&gt;&lt;br /&gt;
---&lt;br /&gt;
題外話，研究一下Python的source code，&lt;br /&gt;
在CPython裡，每個PyObject都有一個記reference count的變數，此變數為&lt;b&gt;ob_refcnt&lt;/b&gt;。所以可以自己寫一個get reference count的function。寫在c/c++ code裡，然後用SWIG轉成python module，取得Python object正確的reference count。&lt;br /&gt;
&lt;pre class="prettyprint"&gt;int GetReferenceCount(PyObject *obj)
{
    return obj ?&amp;nbsp; obj-&amp;gt;ob_refcnt : 0;
}&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5817647334262996203-4508536711214491578?l=falldog7.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://feedproxy.google.com/~r/Falldog/~3/8hbT0W-VNKI/python-pyobjetpyobjecttreference-count.html</link><author>noreply@blogger.com (Falldog)</author><thr:total>0</thr:total><feedburner:origLink>http://falldog7.blogspot.com/2011/04/python-pyobjetpyobjecttreference-count.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5817647334262996203.post-916794567575665505</guid><pubDate>Tue, 12 Apr 2011 01:33:00 +0000</pubDate><atom:updated>2011-04-12T16:19:36.127+08:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Python</category><title>[Python] 實作一個PriorityQueue 與 有pause, resume 功能的PriorityTaskThread</title><description>由於project是用Python2.5，要用到PriorityQueue，但是Python2.6以後才支援&lt;a href="http://docs.python.org/library/queue.html#Queue.PriorityQueue"&gt;PriorityQueue&lt;/a&gt;，所以就想說寫個來試試。主要是改寫自Python原有的Queue class，繼承了原有的access blocking的feature，將原本的put改用insert與append，讓有相同priority的task能有先後之分。&lt;br /&gt;
&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;
&lt;b&gt;&lt;span class="Apple-style-span" style="color: #38761d;"&gt;PriorityQueue&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
&lt;pre class="prettyprint"&gt;from __future__ import with_statement

from Queue import Queue
import bisect
from time import time as _time

_DefaultCheckDup = lambda x,y: bool(x==y)

class PQTask(object):
    """ Data structure of task, for PriorityQueue internal use. """
    def __init__(self, pri=0, item=None):
        object.__init__(self)
        self.pri = pri
        self.item = item
    def __cmp__(self, b):
        return cmp(self.pri, getattr(b, 'pri', 0))
    
class PriorityQueue(Queue):
    """
    PriorityQueue, support reorder the task in queue with priority.
    
    insert() : the task will be processed first in the same priority
    append() : the task will be processed later in the same priority
    - checkdup specified
        1. True : check by _DefaultCheckDup()
        2. callable function : check by this function
    If checkdup is specified,
    _put() will try to kill original task in queue then add new task(with last priority)
    """
    def __init__(self, maxsize=0):
        Queue.__init__(self, maxsize)
    
    # remove the default put function, replace it by _append(), _insert()
    def put(self, item, block=True, timeout=None):
        raise NotImplementedError
    def put_nowait(self, item):
        raise NotImplementedError
    
    def clear(self):
        """ clear all task in queue """
        with self.mutex:
            self.queue = list()
    
    def insert(self, priority, item, checkdup=None, block=True, timeout=None):
        """insert into the queue in the same priority."""
        self.__put(False, priority, item, checkdup, block, timeout)
    def insert_nowait(self, priority, item, checkdup=None):
        """insert item into the queue without blocking."""
        self.__put(False, priority, item, checkdup, False)
        
    def append(self, priority, item, checkdup=None, block=True, timeout=None):
        """append item into the queue in the same priority."""
        self.__put(True, priority, item, checkdup, block, timeout)
    def append_nowait(self, priority, item, checkdup=None):
        """append item into the queue without blocking."""
        self.__put(True, priority, item, checkdup, False)
    
    def __put(self, append, priority, item, checkdup=None, block=True, timeout=None):
        """ reference &amp;amp; modify from Queue::put(), 
            for add custom parameter into _put() """
        self.not_full.acquire()
        try:
            if not block:
                if self._full():
                    raise Full
            elif timeout is None:
                while self._full():
                    self.not_full.wait()
            else:
                if timeout &amp;lt; 0:
                    raise ValueError("'timeout' must be a positive number")
                endtime = _time() + timeout
                while self._full():
                    remaining = endtime - _time()
                    if remaining &amp;lt;= 0.0:
                        raise Full
                    self.not_full.wait(remaining)
            
            #add into queue
            self._put(append, priority, item, checkdup)
            
            self.unfinished_tasks += 1
            self.not_empty.notify()
        finally:
            self.not_full.release()
            
    # Initialize the queue representation
    def _init(self, maxsize):
        self.maxsize = maxsize
        
        #the last item is highest priority
        # queue : [ low priority -&amp;gt; high priority ]
        # get() will try to get last item to process
        self.queue = list()
    
    # put task into queue
    def _put(self, append, p, item, checkdup):
        """ if checkdup is set, check the task is duplicate in queue before add """
        if checkdup:
            if not callable(checkdup):
                checkdup = _DefaultCheckDup
            for idx, qt in enumerate(self.queue):
                if checkdup(qt.item, item):
                    # remove original and add new task in new priority
                    del self.queue[idx]
                    break
        t = PQTask(p, item)
        if append:
            bisect.insort_left(self.queue, t)
        else:
            bisect.insort_right(self.queue, t)
    
    # Get an item from the queue
    def _get(self):
        return self.queue.pop() #get the last(priority largest) task
&lt;/pre&gt;&lt;br /&gt;
&lt;br /&gt;
既然有了PriorityQueue了，就可以用這個class去實作一個PriorityThread了。&lt;br /&gt;
並實作了pause, resume與stop的功能，在測試了很多次後，應該是不會有deadlock啦，有的話請告訴我...XD&lt;br /&gt;
&lt;b&gt;&lt;span class="Apple-style-span" style="color: #38761d;"&gt;PriorityThread&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
&lt;pre class="prettyprint"&gt;from __future__ import with_statement

import threading
import time

SUPER_PRIORITY = 9999

class PriorityThread(threading.Thread):
    """
    PriorityThread, support pause, resume and blocking priority queue
    
    Please overwrite processTask() to do sometime when get task
    follow the feature of PriorityQueue, insertTask() &amp;amp; appendTask()
    should pass the correct priority into queue
    """
    def __init__(self, daemon=None):
        threading.Thread.__init__(self)
        
        self.queue = PriorityQueue()
        
        self.wait     = threading.Condition(threading.Lock()) #wait when pauseEvt is set
        self.pauseEvt = threading.Event()
        self.stopEvt  = threading.Event()
        
        if daemon is not None:
            self.setDaemon(daemon)
        
    def pause(self):
        with self.wait:
            self.pauseEvt.set()
            if self.queue.empty():
                #thread is bolcing in queue.get(), put a None task
                self.insertTask(SUPER_PRIORITY, None)
                
    def resume(self):
        with self.wait:
            self.pauseEvt.clear()
            self.wait.notify()
            
    def stop(self, timeout=None):
        self.stopEvt.set()
        with self.wait:
            self.pauseEvt.clear()
            self.wait.notify()
            if self.queue.empty():
                #thread is bolcing in queue.get(), put a None task
                self.insertTask(SUPER_PRIORITY, None)
        self.join(timeout)
        
    def insertTask(self, priority, item, *argv, **argd):
        self.queue.insert(priority, item, *argv, **argd)
        
    def appendTask(self, priority, item, *argv, **argd):
        self.queue.append(priority, item, *argv, **argd)
    
    def clearTask(self):
        self.queue.clear()
    
    def lenTask(self):
        return self.queue.qsize()
    
    def emptyTask(self):
        return self.queue.empty()
    
    def run(self):
        print '[PriorityThread] %s run()' % (type(self).__name__)
        self.onThreadBegin()
        
        while not self.stopEvt.isSet():
            with self.wait:
                if self.pauseEvt.isSet():
                    self.wait.wait()
                    continue
                    
            t = self.queue.get()
            if t.item:
                self.processTask(t.pri, t.item)
            
            time.sleep(0.01)
            
        self.onThreadEnd()
        print '[PriorityThread] %s end of run()' % (type(self).__name__)
    
    ##############################################
    # Overwriteable function
    ##############################################
    def onThreadBegin(self):
        """ overwrite this function for process something before thread.run() """
        pass
        
    def onThreadEnd(self):
        """ overwrite this function for process something after thread.run() """
        pass
    
    def processTask(self, priority, item):
        """ overwrite this function for process task """
        pass&lt;/pre&gt;&lt;br /&gt;
以下是我的&lt;b&gt;&lt;span class="Apple-style-span" style="color: #38761d;"&gt;TestCase&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
&lt;pre class="prettyprint"&gt;if __name__ == '__main__':
    ####################################
    #        Test PriorityQueue        #
    ####################################
    def TestQueue():
        print '@TestQueue'
        q = PriorityQueue()
        q.insert(0, 'a')
        q.insert(1, 'b')
        q.insert(2, 'c')
        q.insert(3, 'd')
        q.append(3, 'e')
        q.insert(3, 'f')
        q.insert(1, 'b')
        q.insert(0, 'a')
        while not q.empty():
            print q.get().item
    
    def TestQueue_CheckDup():
        print '@TestQueue_CheckDup'
        q = PriorityQueue()
        q.insert(0, 'a', checkdup=True)
        q.insert(1, 'a', checkdup=True)
        q.insert(2, 'a', checkdup=True)
        q.insert(0, 'b', checkdup=True)
        q.insert(1, 'b', checkdup=True)
        #&amp;gt;&amp;gt;&amp;gt; the queue result : [ (1, b), (2, a) ]
        while not q.empty():
            t = q.get()
            print t.pri, t.item
            
    def TestQueue_CheckDupCustomTask():
        ''' Custom _Item, and custom checkdup function '''
        print '@TestQueue_CheckDupCustomTask'
        class _Item:
            def __init__(self, v):
                self.val = v
        def _checkdup(x,y):
            return bool(x.val == y.val)
        q = PriorityQueue()
        q.insert(0, _Item('a'), checkdup=_checkdup)
        q.insert(1, _Item('a'), checkdup=_checkdup)
        q.insert(2, _Item('a'), checkdup=_checkdup)
        q.insert(0, _Item('b'), checkdup=_checkdup)
        q.insert(1, _Item('b'), checkdup=_checkdup)
        #&amp;gt;&amp;gt;&amp;gt; the queue result : [ (1, b), (2, a) ]
        while not q.empty():
            t = q.get()
            print t.pri, t.item.val
    
    TestQueue()
    TestQueue_CheckDup()
    TestQueue_CheckDupCustomTask()
    
    
    ###################################
    #       Test PriorityThread       #
    ###################################
    class MyPriorityThread(PriorityThread):
        def processTask(self, pri, item):
            print item
    
    def TestThread_PauseFirst(t):
        t.pause()
        for v in xrange(100):
            t.appendTask(0, v)
        time.sleep(3)
        t.resume()
        time.sleep(10)
        
    def TestThread_Normal(t):
        for v in xrange(100):
            t.appendTask(0, v)
        time.sleep(0.1)
        t.pause()
        for v in xrange(100, 200):
            t.appendTask(0, v)
        time.sleep(0.1)
        t.resume()
        
        for v in xrange(200, 30000):
            t.appendTask(0, v)
        time.sleep(0.1)
        
    def TestThread_PauseResume(t):
        for v in xrange(10000):
            t.appendTask(0,v)
        time.sleep(0)
        
        while not t.emptyTask():
            import thread
            thread.start_new_thread(lambda t:t.pause(), (t,))
            thread.start_new_thread(lambda t:t.resume(), (t,))
            time.sleep(1)
            
    def TestThread_Control(t):
        print '\n\n=== Command control thread ===\ni:initial and add large task \np:pause, \nr:resume \ns:stop \na:add tasks '
        t.pause()
        
        count = 0
        while not t.emptyTask():
            cmd = raw_input()
            cmd = cmd.strip()
            if cmd == 'i':
                t.resume()
                [ t.appendTask(0,c) for c in range(count, count+5000) ]
                count += 5000
            if cmd == 'p':
                t.pause()
            elif cmd == 'r':
                t.resume()
            elif cmd == 'a':
                [ t.appendTask(0,c) for c in range(count, count+100) ]
                count += 100
                print 'current task count = %d, largets task = %d' % (t.lenTask(), count)
            elif cmd == 's':
                t.stop()
                break
        
    t = MyPriorityThread()
    t.start()
    
    #TestThread_Normal(t)
    #TestThread_PauseFirst(t)
    #TestThread_PauseResume(t)
    TestThread_Control(t)
    
    t.stop()
    
    print 'Please press enter to continue...'
    raw_input()
&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5817647334262996203-916794567575665505?l=falldog7.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://feedproxy.google.com/~r/Falldog/~3/KXku1KHlDWY/python-priorityqueue-pause-resume_12.html</link><author>noreply@blogger.com (Falldog)</author><thr:total>0</thr:total><feedburner:origLink>http://falldog7.blogspot.com/2011/04/python-priorityqueue-pause-resume_12.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5817647334262996203.post-1698099519735796489</guid><pubDate>Thu, 07 Apr 2011 07:28:00 +0000</pubDate><atom:updated>2011-07-03T14:56:34.940+08:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Python</category><title>[Python] Hook stdout後 print會出現 UnicodeDecodeError</title><description>在Python裡，字串的表達方式分為兩種，一種是常見的ansi string：&lt;b&gt;"abc"&lt;/b&gt;，另一種則是unicode：&lt;b&gt;u"abc"&lt;/b&gt;，而OS在秀出文字到window上時，其實都會轉換到使用者設定的code page後才秀出來的。簡單來說，繁體中文有一個對應的code page(cp950)，簡體中文也有個對應的code page(cp936)，如果一個unicode的字串參考錯誤的code page轉換出來的字串就有可能會變成亂碼了。&lt;br /&gt;
&lt;br /&gt;
&lt;a name='more'&gt;&lt;/a&gt;如果有hook stdout的需求的話，通常會把sys.stdout指向自行定義的objecct身上，以下這個範例是實作一個&lt;b&gt;HookStdOut&lt;/b&gt;，將output string重新導向stdout與debug message&lt;br /&gt;
&lt;pre class="prettyprint"&gt;import sys
class HookStdOut(object):
    def __init__(self, *argv, **argd):
        object.__init__(self)
        
    def write(self, s):
        import ctypes
        if isinstance(s, unicode):
            ctypes.windll.kernel32.OutputDebugStringW(s)
        else:
            ctypes.windll.kernel32.OutputDebugStringA(s)
        sys.__stdout__.write(s)

sys.stdout = HookStdOut()
s = unichr(0x5927) + unichr(0x5BB6) + unichr(0x597D) #in cp950 (大, 家, 好)
try:
    print s
except:
    import traceback
    traceback.print_exc()
&lt;/pre&gt;&lt;br /&gt;
但是這個方法如果在print unicode時，就會有exception出現 &lt;b&gt;&lt;i&gt;&lt;span class="Apple-style-span" style="color: #cc0000;"&gt;UnicodeEncodeError&lt;/span&gt;: 'ascii' codec can't encode characters in position 0-2: ordinal not in range(128)&lt;/i&gt;&lt;/b&gt;&lt;br /&gt;
這是因為Python在print unicode到stdout前，會試著把unicode以console code page做encode的動作，再write到stdout。而現在stdout是我們自行定義的HookStdOut，最後write到stdout時，只會以ascii的方式encode，然後就會出現UnicodeEncodeError了。&lt;br /&gt;
&lt;br /&gt;
研究了一下Python的source code...&lt;br /&gt;
&lt;b&gt;&lt;i&gt;&lt;span class="Apple-style-span" style="color: #6aa84f;"&gt;Python\sysmodule.c&lt;/span&gt;&lt;/i&gt;&lt;/b&gt;&lt;br /&gt;
&lt;pre class="prettyprint"&gt;PyObject *
_PySys_Init(void)
{
    //...
    sysout = PyFile_FromFile(stdout, "&amp;lt;stdout&amp;gt;", "w", _check_and_flush);
    //...
    if(isatty(_fileno(stdout)) &amp;amp;&amp;amp; PyFile_Check(sysout)) {
        sprintf(buf, "cp%d", GetConsoleOutputCP());
        if (!PyFile_SetEncoding(sysout, buf))
            return NULL;
    }
    //...
}&lt;/pre&gt;&lt;b&gt;&lt;i&gt;&lt;span class="Apple-style-span" style="color: #6aa84f;"&gt;Objects\fileobject.c&lt;/span&gt;&lt;/i&gt;&lt;/b&gt;&lt;br /&gt;
&lt;pre class="prettyprint"&gt;int
PyFile_WriteObject(PyObject *v, PyObject *f, int flags)
{
    PyObject *writer, *value, *args, *result;
    if (f == NULL) {
        PyErr_SetString(PyExc_TypeError, "writeobject with NULL file");
        return -1;
    }
    else if (PyFile_Check(f)) {
        FILE *fp = PyFile_AsFile(f);
#ifdef Py_USING_UNICODE
        PyObject *enc = ((PyFileObject*)f)-&amp;gt;f_encoding;
        int result;
#endif
        if (fp == NULL) {
            err_closed();
            return -1;
        }
#ifdef Py_USING_UNICODE
                if ((flags &amp;amp; Py_PRINT_RAW) &amp;amp;&amp;amp;
            PyUnicode_Check(v) &amp;amp;&amp;amp; enc != Py_None) {
            char *cenc = PyString_AS_STRING(enc);
            value = PyUnicode_AsEncodedString(v, cenc, "strict");
            if (value == NULL)
                return -1;
        } else {
            value = v;
            Py_INCREF(value);
        }
        result = PyObject_Print(value, fp, flags);
        Py_DECREF(value);
        return result;
#else
        return PyObject_Print(v, fp, flags);
#endif
    }
    //...
}&lt;/pre&gt;在Python default的sys.stdout，其實是一個FileObject，會以Windows API&amp;nbsp;&lt;a href="http://msdn.microsoft.com/en-us/library/ms683162(v=vs.85).aspx"&gt;GetConsoleCP()&lt;/a&gt;將console code page 記錄在f_encoding這個變數裡，等到print時會call進PyFile_WriteObject()，如果要print的PyObject *v是PyUnicode的話，會先將PyUnicode以f_encoding做encode，然後再print出去。&lt;br /&gt;
&lt;br /&gt;
而我們實作了一個HookStdOut，但是我們並沒有指定它的encoding是什麼，所以default是ascii，在嘗試print unicode時，就會出現exception了。所以，我們必須要在write()裡自己encode到正確的code page才不會有這個exception出現。&lt;br /&gt;
&lt;b&gt;&lt;span class="Apple-style-span" style="color: #0b5394;"&gt;正確版&lt;/span&gt;的範例&lt;/b&gt;：&lt;br /&gt;
&lt;pre class="prettyprint"&gt;import sys
class HookStdOut(object):
    def __init__(self, *argv, **argd):
        object.__init__(self)
        self.encoding = sys.getfilesystemencoding()
    def write(self, s):
        import ctypes
        if isinstance(s, unicode):
            ctypes.windll.kernel32.OutputDebugStringW(s)
            sys.__stdout__.write(s.encode(self.encoding)) #try to encode the unicode to default file system encoding
        else:
            ctypes.windll.kernel32.OutputDebugStringA(s)
            sys.__stdout__.write(s)

sys.stdout = HookStdOut()
s = unichr(0x5927) + unichr(0x5BB6) + unichr(0x597D) #in cp950 (大, 家, 好)
try:
    print s
except:
    import traceback
    traceback.print_exc()
&lt;/pre&gt;&lt;br /&gt;
&lt;br /&gt;
其實還有另一個方法可以避掉UnicodeEncodeError的exception，但是並&lt;b&gt;&lt;i&gt;不建議&lt;/i&gt;&lt;/b&gt;這麼做。&lt;br /&gt;
&lt;pre class="prettyprint"&gt;class HookStdOut(object):
    def __init__(self, *argv, **argd):
        object.__init__(self)
        
    def write(self, s):
        import ctypes
        if isinstance(s, unicode):
            ctypes.windll.kernel32.OutputDebugStringW(s)
        else:
            ctypes.windll.kernel32.OutputDebugStringA(s)
        sys.__stdout__.write(s)

#reset default encoding!!!
reload(sys)
sys.setdefaultencoding(sys.getfilesystemencoding())

sys.stdout = HookStdOut()
s = unichr(0x5927) + unichr(0x5BB6) + unichr(0x597D) #in cp950 (大, 家, 好)
try:
    print s
except:
    import traceback
    traceback.print_exc()
&lt;/pre&gt;由於在Python2.5的site.py將sys.setdefaultencoding remove掉了，所以必須要reload sys module，然後再setdefaultencoding一次才行。&lt;br /&gt;
但是參考一下這篇文章，&lt;a href="http://tarekziade.wordpress.com/2008/01/08/syssetdefaultencoding-is-evil/"&gt;setdefaultencoding is evil&lt;/a&gt;，我想，在小程式裡可能可以用setdefaultencoding的方式解掉，但如果是大型的project的話，並非所有的unicode會用相同的encoding，所以還是避免用這樣的方式比較好。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;延伸閱讀&lt;/b&gt;&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&lt;a href="http://docs.python.org/howto/unicode.html"&gt;Python官網 - Unicode How To&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.joelonsoftware.com/articles/Unicode.html"&gt;The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets&lt;/a&gt;&amp;nbsp;- (&lt;a href="http://local.joelonsoftware.com/wiki/The_Joel_on_Software_Translation_Project:%E8%90%AC%E5%9C%8B%E7%A2%BC"&gt;中譯版&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5817647334262996203-1698099519735796489?l=falldog7.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://feedproxy.google.com/~r/Falldog/~3/ExsKkhjumvc/python-hook-stdout-print.html</link><author>noreply@blogger.com (Falldog)</author><thr:total>0</thr:total><feedburner:origLink>http://falldog7.blogspot.com/2011/04/python-hook-stdout-print.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5817647334262996203.post-3606404617009227301</guid><pubDate>Tue, 21 Dec 2010 17:22:00 +0000</pubDate><atom:updated>2010-12-22T01:24:56.966+08:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">emomeDDSMS</category><title>[emomeDDSMS] 下載emome上的備份簡訊 更新0.73</title><description>應觀眾要求，新增功能，輸出傳送簡訊的號碼與通訊錄的暱稱。&lt;br /&gt;
下載連結(按右鍵另存新檔)：&lt;a href="http://dl.dropbox.com/u/17213022/emomeDDSMS/emomeDDSMS.0.73.js"&gt;emomeDDSMS 0.73&lt;/a&gt; (2010/12/22)&lt;br /&gt;
Change Log：&lt;br /&gt;
1. Add output phone number and nick name function -&amp;nbsp;GetPhoneBook() and&amp;nbsp;ConvertPhonelist()&lt;br /&gt;
&lt;br /&gt;
使用說明，請參考&lt;a href="http://falldog7.blogspot.com/2009/08/emomeddsms-emome.html"&gt;前一篇&lt;/a&gt;文章。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5817647334262996203-3606404617009227301?l=falldog7.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://feedproxy.google.com/~r/Falldog/~3/aWZgikWXGIQ/emomeddsms-emome-073.html</link><author>noreply@blogger.com (Falldog)</author><thr:total>3</thr:total><feedburner:origLink>http://falldog7.blogspot.com/2010/12/emomeddsms-emome-073.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5817647334262996203.post-8541522366614063369</guid><pubDate>Tue, 28 Sep 2010 14:50:00 +0000</pubDate><atom:updated>2010-09-28T22:51:59.308+08:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">emomeDDSMS</category><title>[emomeDDSMS] 下載emome上的備份簡訊 更新0.72</title><description>因應emome網頁些許的更新與問題，emomeDDSMS也要稍作修改。&lt;br /&gt;
下載連結(按右鍵另存新檔)：&lt;a href="http://www.cs.nctu.edu.tw/~skshie/software/emomeDDSMS/emomeDDSMS.0.72.js"&gt;emomeDDSMS 0.72&lt;/a&gt; (2010/9/28)&lt;br /&gt;
Change Log：&lt;br /&gt;
1. emome browse sms page changed, 'from' action changed to 'POST', modify related url actions.&lt;br /&gt;
2. Add ResetPage() mechanism for emome website issue, sometimes can't browse normal&lt;br /&gt;
3. Add description, suggest to download file to D disk&lt;br /&gt;
&lt;br /&gt;
使用說明，請參考&lt;a href="http://falldog7.blogspot.com/2009/08/emomeddsms-emome.html"&gt;前一篇&lt;/a&gt;文章。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5817647334262996203-8541522366614063369?l=falldog7.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://feedproxy.google.com/~r/Falldog/~3/LOk0gUbRaQ8/emomeddsms-emome-072.html</link><author>noreply@blogger.com (Falldog)</author><thr:total>4</thr:total><feedburner:origLink>http://falldog7.blogspot.com/2010/09/emomeddsms-emome-072.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5817647334262996203.post-4661901363565803161</guid><pubDate>Tue, 11 May 2010 17:14:00 +0000</pubDate><atom:updated>2010-05-12T01:14:18.984+08:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">SudokuBoxer</category><title>[SudokuBoxer] Project 轉移至 SourceForge</title><description>一開始將 Project 放在Google code，連線至SVN的速度還不錯，介面操作很陽春，但是也很方便。不過使用了一陣子後，發現放在上面供人下載的檔案，下載次數有著砂鍋大的問題，不管下載幾次，次數都不會增加，這樣子的結果實在令人傷心…到Google code的論壇發問，才知道原來這個 issue 已經 create 出來很久了，早在2009/12時就已經存在了，但是到現在還沒修好，這效率著實令人吃驚。&lt;br /&gt;
&lt;br /&gt;
所以，才將 Project 轉移至 SourceForge，應該是之前有開過 Project 的關係，開新 Project 時也不需要審核，而且開新 Project 的步驟與介面也不像之前讓人退避三舍。上傳檔案的部分也有很大的進步(以前一定要在command line底下上傳才行)，現在只要在網頁上東按西按就可以上傳了。重點是 Download 次數的統計實在比Google code來得好多了。&lt;br /&gt;
&lt;br /&gt;
有興趣的人可以下載來玩玩，更新了不少東西&amp;nbsp; :)&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_azUech_ubi0/S-mQVSzbBlI/AAAAAAAAAZo/PzjnZmFBgKc/s1600/sudokuboxer.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/_azUech_ubi0/S-mQVSzbBlI/AAAAAAAAAZo/PzjnZmFBgKc/s320/sudokuboxer.JPG" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&lt;a href="https://sourceforge.net/projects/sudokuboxer/"&gt;SudokuBoxer SourceForge&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://sourceforge.net/projects/sudokuboxer/files/"&gt;SudokuBoxer 下載頁面&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5817647334262996203-4661901363565803161?l=falldog7.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://feedproxy.google.com/~r/Falldog/~3/mUvwWR2n_pk/sudokuboxer-project-sourceforge.html</link><author>noreply@blogger.com (Falldog)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/_azUech_ubi0/S-mQVSzbBlI/AAAAAAAAAZo/PzjnZmFBgKc/s72-c/sudokuboxer.JPG" height="72" width="72" /><thr:total>2</thr:total><feedburner:origLink>http://falldog7.blogspot.com/2010/05/sudokuboxer-project-sourceforge.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5817647334262996203.post-8240097936852424953</guid><pubDate>Thu, 25 Mar 2010 12:05:00 +0000</pubDate><atom:updated>2010-03-25T20:05:47.150+08:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Python</category><category domain="http://www.blogger.com/atom/ns#">wxPython</category><category domain="http://www.blogger.com/atom/ns#">SudokuBoxer</category><title>[SudokuBoxer] wxPython 實作Sudoku GUI Game</title><description>前一陣子利用空閒時間練習了一下wxPython，順便寫了一個Sudoku的小遊戲，想說完成的話，可以給我媽玩一下。&lt;br /&gt;
&lt;br /&gt;
目前的功能還很陽春，不過至少題目的難易度滿正確的，在產生正確的題目上費了不少功夫，曾經嘗試過連到某Sudoku網頁去解析題目網頁的html語法，然後再儲存到DB裡，可是這招實在是太sucks了，抓不到50題，就被擋IP了 XD (看來是sleep的間隔時間不夠長.... ) 後來還找了一些tool來產生題庫，但是效果都不盡理想，不是題目有問題，就是題目難易度不均。&lt;br /&gt;
&lt;br /&gt;
後來終於找到一個 Sudoku 產生題庫的 tool，跟一個可以幫題目打分數的 tool。雙管其下的結果還算讓人滿意。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;a href="http://sudoku.latte.ca/"&gt;Sudoku Importer&lt;/a&gt; - 以挖洞法產生sudoku題庫，所以必須餵入題目挖洞的template&lt;br /&gt;
&lt;a href="http://diuf.unifr.ch/people/juillera/Sudoku/Sudoku.html"&gt;Sudoku Explainer&lt;/a&gt; - 一個強大的Java GUI Sudoku軟體，可以教你怎麼一步步解題，以及解題所需要的技巧，最重要的是可以餵給它題目，然後產生該sudoku的難度分數以及解題所需要的技巧。&lt;br /&gt;
改天再寫一篇介紹怎麼用這兩個 tool 吧。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;div style="text-align: center;"&gt;SudokuBoxer遊戲畫面&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_azUech_ubi0/S6tORhwiCxI/AAAAAAAAAZg/BiKYUf_ORIw/s1600/1675313524%282%29.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="320" src="http://2.bp.blogspot.com/_azUech_ubi0/S6tORhwiCxI/AAAAAAAAAZg/BiKYUf_ORIw/s320/1675313524%282%29.jpg" width="265" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&lt;a href="http://code.google.com/p/sudokuboxer/"&gt;SudokuBoxer Google Code Project 首頁&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://code.google.com/p/sudokuboxer/downloads/list"&gt;SudokuBoxer Download page&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;SudokuBoxer是用wxPython實作的，可惜的就是執行檔大了一點， 壓縮完後竟然還要5MB，沒壓縮也要15MB，真是誇張。&lt;br /&gt;
&lt;br /&gt;
這也是我第一次用wxPython，第一次自己動手用 gettext 作 Multi-Language，程式還有很多功能沒完成，不過應該是不會輕易當掉啦，呵。想說弄到一個段落就放上來Share給大家一下。Python上手後，真的是快速開發的好物啊！&lt;br /&gt;
&lt;br /&gt;
可惜 wxPython(wxWidgets) 在繪圖上的功能過於陽春，連 Texture 之間的 Alpha Blending 功能都沒有，不過wxWidgets可以貼OpenGL的Canvas上去，應該可以補足這一塊，但還要花時間學OpenGL就是了，大學學過都還給老師了....&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5817647334262996203-8240097936852424953?l=falldog7.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://feedproxy.google.com/~r/Falldog/~3/sA4e0ozcuI8/sudokuboxer-wxpython-sudoku-gui-game.html</link><author>noreply@blogger.com (Falldog)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/_azUech_ubi0/S6tORhwiCxI/AAAAAAAAAZg/BiKYUf_ORIw/s72-c/1675313524%282%29.jpg" height="72" width="72" /><thr:total>1</thr:total><feedburner:origLink>http://falldog7.blogspot.com/2010/03/sudokuboxer-wxpython-sudoku-gui-game.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5817647334262996203.post-6292895174428271250</guid><pubDate>Sun, 21 Mar 2010 16:02:00 +0000</pubDate><atom:updated>2010-03-22T00:02:48.150+08:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">emomeDDSMS</category><title>[emomeDDSMS] 下載emome上的備份簡訊 更新0.71</title><description>因應emome網頁些許的更新，emomeDDSMS也要稍作修改。&lt;br /&gt;
下載連結：&lt;a href="http://www.cs.nctu.edu.tw/%7Eskshie/software/emomeDDSMS/emomeDDSMS.0.71.js"&gt;emomeDDSMS 0.71&lt;/a&gt; (2010/3/21)&lt;br /&gt;
Change Log：&lt;br /&gt;
1. Modify login.js path in Login() &lt;br /&gt;
2. Modify @name to @user_name, because unknow Chickenfoot issue to use parameter @name.&lt;br /&gt;
&lt;br /&gt;
使用說明，請參考&lt;a href="http://falldog7.blogspot.com/2009/08/emomeddsms-emome.html"&gt;前一篇&lt;/a&gt;文章。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5817647334262996203-6292895174428271250?l=falldog7.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://feedproxy.google.com/~r/Falldog/~3/iITAE5oC--I/emomeddsms-emome-071.html</link><author>noreply@blogger.com (Falldog)</author><thr:total>8</thr:total><feedburner:origLink>http://falldog7.blogspot.com/2010/03/emomeddsms-emome-071.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5817647334262996203.post-796405734029529784</guid><pubDate>Fri, 26 Feb 2010 09:38:00 +0000</pubDate><atom:updated>2011-04-07T15:36:57.922+08:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">wxWidgets</category><category domain="http://www.blogger.com/atom/ns#">Python</category><category domain="http://www.blogger.com/atom/ns#">wxPython</category><title>[wxPython] 實作多國語言MUI by GetText</title><description>wxPython提供了方便的支援多國語言API，結合&lt;a href="http://www.gnu.org/software/gettext/"&gt;GNU GetText project&lt;/a&gt;，使用上很是方便。&lt;br /&gt;
由GetText parse 檔案後，建出PO檔然後轉成MO檔，就可以給wxPython讀取使用。&lt;br /&gt;
&lt;br /&gt;
&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
首先，先撰寫wxPython的code&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="prettyprint"&gt;#!/usr/bin/python

import wx
_ = wx.GetTranslation

class Translation(wx.Frame):
    def __init__(self, parent, id, title):
        wx.Frame.__init__(self, parent, id, title, size=(220, 100))

        panel = wx.Panel(self, -1)

        wx.StaticText(panel, -1, _("Hello"), (10, 10))
        
        self.Centre()
        self.Show(True)

app = wx.App()

mylocale = wx.Locale()
mylocale.AddCatalogLookupPathPrefix('.')
mylocale.AddCatalog('CHT') #Use CHT.mo

Translation(None, -1, 'Translation')
app.MainLoop()
&lt;/pre&gt;&lt;br /&gt;
&lt;div style="text-align: center;"&gt;執行畫面&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_azUech_ubi0/S6rBGy6q7kI/AAAAAAAAAZM/7N65jTWo5BM/s1600/wxPython-MUI-ENU.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/_azUech_ubi0/S6rBGy6q7kI/AAAAAAAAAZM/7N65jTWo5BM/s320/wxPython-MUI-ENU.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
&lt;br /&gt;
使用 wx.Locale 的 &lt;b style="color: #990000;"&gt;AddCatalog&lt;/b&gt;()，wxPython就會去搜尋目前的目錄、系統目錄，或是透過&lt;b style="color: #990000;"&gt;AddCatalogLookupPathPrefix&lt;/b&gt;()指定的路徑。&lt;br /&gt;
然後將 wx.GetTranslation 指定成 &lt;b style="color: #990000;"&gt;_&lt;/b&gt; ，這樣子我們只要對想翻譯的字串"Hello"改成&lt;b style="color: #990000;"&gt;_(&lt;/b&gt;"Hello"&lt;b style="color: #990000;"&gt;)&lt;/b&gt;就可以了。&lt;br /&gt;
&lt;i&gt;&lt;b&gt;Tip:&lt;/b&gt;&lt;/i&gt; &lt;i style="color: #444444;"&gt;GetText建立PO檔時，只會針對_("")裡面的字串做處理。&lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
接下來必須下載 GetText 的 Tool 才能建立翻譯字串所需的PO檔跟MO檔。&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.gnu.org/software/gettext/"&gt;GNU GetText home page&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://gnuwin32.sourceforge.net/packages/gettext.htm"&gt;GNU GetText for Windows下載連結&lt;/a&gt;，選擇Complete package, except sources，下載後安裝，就會幫你把一切的 dependency 搞定了。&lt;/li&gt;
&lt;/ul&gt;安裝完GetText之後，就有一些執行檔可以使用了，以下介紹幾個最需要用到的： &lt;br /&gt;
&lt;ul&gt;&lt;/ul&gt;&lt;div style="color: #073763;"&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;xgettext.exe&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;將 input 檔案內的翻譯字串收集後，儲存成PO檔。&lt;br /&gt;
&lt;b&gt;xgettext&lt;/b&gt;&lt;i&gt; [option] [inputfile] ..&lt;/i&gt;.&lt;br /&gt;
'&lt;span style="color: #bf9000;"&gt;inputfile ...&lt;/span&gt;' : 處理此file&lt;br /&gt;
'&lt;span style="color: #bf9000;"&gt;-f file&lt;/span&gt;', '&lt;span style="color: #bf9000;"&gt;--files-from=file&lt;/span&gt;' ：處理file內的儲存的file name&lt;br /&gt;
'&lt;span style="color: #bf9000;"&gt;-d name&lt;/span&gt;', '&lt;span style="color: #bf9000;"&gt;--default-domain=name&lt;/span&gt;' ： 輸出檔名為name.po&lt;br /&gt;
&lt;br /&gt;
因此，我將上面的wxPython檔案存為test.py&lt;br /&gt;
&lt;pre class="cmd"&gt;xgettext  --default-domain=test  test.py&lt;/pre&gt;之後就會輸出一個test.po的檔案，檔案的內容為下列&lt;br /&gt;
&lt;pre class="prettyprint"&gt;# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR &amp;lt;EMAIL@ADDRESS&amp;gt;, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2010-02-26 16:31+0800\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME &amp;lt;EMAIL@ADDRESS&amp;gt;\n"
"Language-Team: LANGUAGE &amp;lt;LL@li.org&amp;gt;\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: 8bit\n"

#: ..\test.py:12
msgid "Hello"
msgstr ""&lt;/pre&gt;&lt;br /&gt;
現在就可以修改&lt;b style="color: #990000;"&gt; test.po&lt;/b&gt; 檔，可以在裡面打入想翻譯的字串，比如將&lt;b style="color: #0c343d;"&gt;"Hello"&lt;/b&gt;翻譯成中文，儲存成&lt;b style="color: #0c343d;"&gt;CHT.po&lt;/b&gt;，將"Hello"翻譯成英文，儲存成&lt;b style="color: #0c343d;"&gt;ENU.po&lt;/b&gt;。&lt;br /&gt;
通常翻譯成非英文的語言，就要將PO檔的 encoding 方式改成&lt;b style="color: #0c343d;"&gt;UTF-8&lt;/b&gt;的格式儲存，才能正確存取。所以要將檔案轉成UTF-8編碼(可以用&lt;a href="http://notepad-plus.sourceforge.net/tw/site.htm"&gt;Notepad++&lt;/a&gt;，轉成UTF-8檔首無BOM)，然後改"Content-Type: text/;lain; charset=CHARSET\n"，將CHARSET改成&lt;b&gt;&lt;span style="color: #990000;"&gt;utf-8&lt;/span&gt;&lt;/b&gt;。&lt;br /&gt;
&lt;pre class="prettyprint"&gt;# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR &amp;lt;EMAIL@ADDRESS&amp;gt;, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2010-02-26 16:31+0800\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME &amp;lt;EMAIL@ADDRESS&amp;gt;\n"
"Language-Team: LANGUAGE &amp;lt;LL@li.org&amp;gt;\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n" #charset
"Content-Transfer-Encoding: 8bit\n"

#: ..\test.py:12
msgid "Hello"
msgstr "哈囉~"&lt;/pre&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;div style="color: #073763;"&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;msgmerge.exe&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;將兩個PO檔，進行Merge的動作，通常是用在PO檔更新時。&lt;br /&gt;
&lt;b&gt;msgmerge&lt;/b&gt;&lt;i&gt;&lt;b&gt; &lt;/b&gt;[option]&lt;/i&gt; def.po ref.po&lt;br /&gt;
'&lt;span style="color: #bf9000;"&gt;def.po&lt;/span&gt;' ： 原本已經翻譯過的PO檔&lt;br /&gt;
'&lt;span style="color: #bf9000;"&gt;ref.po&lt;/span&gt;' ： 新建立好的PO檔&lt;br /&gt;
'&lt;span style="color: #bf9000;"&gt;-U&lt;/span&gt;', '&lt;span style="color: #bf9000;"&gt;--update&lt;/span&gt;' ： 如果def.po已經是最新的，就不做事&lt;br /&gt;
所以，假如我們在test.py裡，加了一個新字串_("Sudoku")後，先執行xgettext產生新的PO檔，再執行msgmerge做merge的動作&lt;br /&gt;
&lt;pre class="cmd"&gt;xgettext  --default-domain=test_new  test.py
msgmerge  --update test.po  test_new.po&lt;/pre&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;div style="color: #073763;"&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;msgfmt.exe&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;將PO檔轉成MO檔 &lt;br /&gt;
&lt;b&gt;msgfmt&lt;/b&gt;&lt;i&gt;&lt;b&gt; &lt;/b&gt;[option]&lt;/i&gt; filename.po&lt;br /&gt;
'&lt;span style="color: #bf9000;"&gt;- o file&lt;/span&gt;', '&lt;span style="color: #bf9000;"&gt;--output-file=file&lt;/span&gt;' ： 指定輸出的檔名&lt;br /&gt;
&lt;pre class="cmd"&gt;msgfmt  --output-file=CHT.mo  test.po&lt;/pre&gt;&lt;br /&gt;
最後，就將中文翻譯的CHT.mo放在test.py檔同個目錄下，執行後應該就會顯示中文了。&lt;br /&gt;
&lt;br /&gt;
&lt;div style="text-align: center;"&gt;執行畫面&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_azUech_ubi0/S6rBSLsLzWI/AAAAAAAAAZU/GjypuWSoJaE/s1600/wxPython-MUI-CHT.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/_azUech_ubi0/S6rBSLsLzWI/AAAAAAAAAZU/GjypuWSoJaE/s320/wxPython-MUI-CHT.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style="text-align: center;"&gt;&lt;/div&gt;&lt;ul&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5817647334262996203-796405734029529784?l=falldog7.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://feedproxy.google.com/~r/Falldog/~3/6cvMn7DY5m0/wxpython-mui-by-gettext.html</link><author>noreply@blogger.com (Falldog)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/_azUech_ubi0/S6rBGy6q7kI/AAAAAAAAAZM/7N65jTWo5BM/s72-c/wxPython-MUI-ENU.jpg" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://falldog7.blogspot.com/2010/02/wxpython-mui-by-gettext.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5817647334262996203.post-7921577593696081499</guid><pubDate>Tue, 22 Dec 2009 02:33:00 +0000</pubDate><atom:updated>2009-12-22T10:35:16.044+08:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Win32</category><title>[Windows] Local time 轉 UTC</title><description>Window提供了 API 可以轉換時間的時區。&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;TzSpecificLocalTimeToSystemTime：Local time -&amp;gt; UTC&lt;/li&gt;
&lt;li&gt;SystemTimeToTzSpecificLocalTime ：UTC -&amp;gt; Local time&lt;/li&gt;
&lt;/ul&gt;第一個參數可指定 &lt;a href="http://msdn.microsoft.com/en-us/library/ms725481%28VS.85%29.aspx"&gt;&lt;b&gt;TIME_ZONE_INFORMATION&lt;/b&gt;&lt;/a&gt;，如果傳進&lt;i&gt;&lt;b&gt; NULL &lt;/b&gt;&lt;/i&gt;的話，即代表目前系統使用的Time Zone。 &lt;br /&gt;
&lt;ul&gt;&lt;/ul&gt;&lt;br /&gt;
&lt;pre class="prettyprint"&gt;SYSTEMTIME ConvertLocalTime2UTC(UINT year, UINT month, UINT day, UINT hour, UINT minute, UINT second)
{
    SYSTEMTIME local, utc;
    ZeroMemory(&amp;amp;local, sizeof(local));
    local.wYear   = year;
    local.wMonth  = month;
    local.wDay    = day;
    local.wHour   = hour;
    local.wMinute = minute;
    local.wSecond = second;
    TzSpecificLocalTimeToSystemTime( NULL, &amp;amp;local, &amp;amp;utc );
    printf("UTC Time  =%d/%d/%d %d:%d:%d\n", utc.wYear, utc.wMonth, utc.wDay, utc.wHour, utc.wMinute, utc.wSecond);
    printf("Local Time=%d/%d/%d %d:%d:%d\n", local.wYear, local.wMonth, local.wDay, local.wHour, local.wMinute, local.wSecond);
    return utc;
}

SYSTEMTIME ConvertUTC2LocalTime(UINT year, UINT month, UINT day, UINT hour, UINT minute, UINT second)
{
    SYSTEMTIME local, utc;
    ZeroMemory(&amp;amp;utc, sizeof(utc));
    utc.wYear   = year;
    utc.wMonth  = month;
    utc.wDay    = day;
    utc.wHour   = hour;
    utc.wMinute = minute;
    utc.wSecond = second;
    SystemTimeToTzSpecificLocalTime( NULL, &amp;amp;utc, &amp;amp;local );
    printf("UTC Time  =%d/%d/%d %d:%d:%d\n", utc.wYear, utc.wMonth, utc.wDay, utc.wHour, utc.wMinute, utc.wSecond);
    printf("Local Time=%d/%d/%d %d:%d:%d\n", local.wYear, local.wMonth, local.wDay, local.wHour, local.wMinute, local.wSecond);
    return local;
}&lt;/pre&gt;&lt;br /&gt;
Reference：&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/ms725485%28VS.85%29.aspx"&gt;TzSpecificLocalTimeToSystemTime Function&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/ms724949%28VS.85%29.aspx"&gt;SystemTimeToTzSpecificLocalTime Function&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5817647334262996203-7921577593696081499?l=falldog7.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://feedproxy.google.com/~r/Falldog/~3/tRuf7IE5ZbY/windows-local-time-utc.html</link><author>noreply@blogger.com (Falldog)</author><thr:total>0</thr:total><feedburner:origLink>http://falldog7.blogspot.com/2009/12/windows-local-time-utc.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5817647334262996203.post-5148604035806057188</guid><pubDate>Fri, 11 Dec 2009 17:35:00 +0000</pubDate><atom:updated>2011-04-07T15:39:43.461+08:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Win32</category><category domain="http://www.blogger.com/atom/ns#">MFC</category><title>[Win32 API] String Conversion</title><description>在Windows底下做字串轉換其實還滿簡單的，在MFC的Library裡，提供了一些簡單的Marco可以用，就可以針對wstring, string, CComBSTR, BSTR之間做轉換了。需 Include &lt;b style="color: #bf9000;"&gt;AtlBase.h&lt;/b&gt;, &lt;b style="color: #bf9000;"&gt;AtlConv.h&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
以下是 &lt;b&gt;ATL7.0&lt;/b&gt; 版 Marco、Class的命名規則&lt;br /&gt;
&lt;div style="background-color: black; color: yellow;"&gt;CSourceType2&lt;i&gt;[C]&lt;/i&gt;DestinationType&lt;i&gt;[EX]&lt;/i&gt;&lt;/div&gt;&lt;br /&gt;
以下是 &lt;b&gt;ATL3.0&lt;/b&gt; 舊版 Marco的命名規則&lt;br /&gt;
&lt;div style="background-color: black; color: yellow;"&gt;SourceType2&lt;i&gt;[C]&lt;/i&gt;DestinationType&lt;i&gt;[EX]&lt;/i&gt;&lt;/div&gt;&lt;br /&gt;
&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
SourceType or DestinationType包含了A, W, T, OLE可使用，Ex: A2W, W2T, T2OLE...&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;新舊版的命名規則差異只有開頭有沒有&lt;i style="color: red;"&gt;&lt;b&gt;C&lt;/b&gt;&lt;/i&gt;，結果有沒有EX。新版的C開頭代表跟舊版的&lt;i&gt;&lt;b&gt;Marco&lt;/b&gt;&lt;/i&gt;不一樣，而是以&lt;i&gt;&lt;b&gt;Class&lt;/b&gt;&lt;/i&gt;去實作的。Ex: A2W, W2A是Marco，CA2W, CW2A則是Class。&lt;/li&gt;
&lt;li&gt;&lt;b&gt;[&lt;span style="color: red;"&gt;C&lt;/span&gt;] &lt;/b&gt;: 中間的C可有可無，代表著DestinationType是否為&lt;b&gt; const &lt;/b&gt;的字串。&lt;/li&gt;
&lt;li&gt;&lt;b&gt;[&lt;span style="color: red;"&gt;EX&lt;/span&gt;]&lt;/b&gt; : 新版的EX表示，可指定Class所使用的&lt;b&gt;Buffer size&lt;/b&gt;。Ex: CA2W&amp;lt;64&amp;gt;&lt;br /&gt;
&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
既然有新版的，當然是用新的好啊，因為用舊版的在使用前，必須手動加一個Marco : &lt;i style="color: #7f6000;"&gt;USES_CONVERSION&lt;/i&gt;才能正常Work。舊版是吃stack的memory，一定要等function離開後才會release。&lt;br /&gt;
&lt;br /&gt;
範例：&lt;br /&gt;
&lt;b&gt;&lt;span style="color: red;"&gt;[錯誤!]&lt;/span&gt;&lt;/b&gt; 將&lt;i style="color: #0b5394;"&gt;&lt;b&gt;ANSI&lt;/b&gt;&lt;/i&gt;的字串轉成&lt;i style="color: #0b5394;"&gt;&lt;b&gt;Unicode&lt;/b&gt;&lt;/i&gt;字串&lt;br /&gt;
&lt;pre class="prettyprint"&gt;LPSTR name = "Falldog"; 
LPWSTR wstr = CA2W(name);
//Use wstr....&lt;/pre&gt;這樣子的寫法，在 ATL3.0 使用A2W是可以work的，但是在 ATL7.0 的版本中，CA2W是一個class，所以意義上會變得不太一樣。&lt;br /&gt;
將上面的範例做慢動作解析：&lt;br /&gt;
&lt;pre class="prettyprint"&gt;LPSTR name = "Falldog"; 
LPWSTR wstr;
{
    CA2W temp(name);
    wstr = temp.operator LPWSTR(); 
}
//Use wstr.... but memory stored in temp is destroyed...&amp;nbsp;&lt;/pre&gt;&lt;pre class="prettyprint"&gt;//再把上面的有問題的地方轉成平常可能看到的畫面
LPWSTR my_func_CA2W( /*LPSTR ansi*/)
{
    WCHAR* temp = L"Falldog";
    return temp;
}
LPWSTR wstr = my_func_CA2W();
//Use wstr....&lt;/pre&gt;下半部出現的問題是，當 my_func_CA2W 將 temp return 回來後，其實儲存字串內容的 memory 就已經被 release 掉了，所以當去 access wstr 時，就會有 exception 了。&lt;br /&gt;
而上半部跟下半部的問題是一樣的，當你 create 了一個CA2W的object，但是卻把它 assign 給一個 pointer，而 CA2W 的 &lt;i&gt;life scope&lt;/i&gt; 在 assign 給 pointer 之後就結束了。當然使用者再使用 wstr 後，會出現 exception。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;div style="color: red;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;b style="color: #38761d;"&gt;&lt;span style="color: red;"&gt;[正解1]&lt;/span&gt; &lt;/b&gt;將ANSI的字串轉成Unicode字串 (可重複使用轉換後字串) &lt;br /&gt;
&lt;pre class="prettyprint"&gt;LPSTR name = "Falldog"; 
CA2W wstr(name);
//Use wstr...&lt;/pre&gt;&lt;br /&gt;
&lt;b style="color: #38761d;"&gt;&lt;span style="color: red;"&gt;[正解2]&lt;/span&gt; &lt;/b&gt;將ANSI的字串轉成Unicode字串 (只用一次, &lt;strike&gt;射後不理&lt;/strike&gt;) &lt;br /&gt;
&lt;pre class="prettyprint"&gt;LPSTR name = "Falldog"; 
wprintf( L"User Unicode Name=%s", CA2W(name) );&lt;/pre&gt;&lt;br /&gt;
Reference :&lt;a href="http://msdn.microsoft.com/en-us/library/87zae4a3%28VS.80%29.aspx"&gt; [MSDN] ATL and MFC String Conversion Macros&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5817647334262996203-5148604035806057188?l=falldog7.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://feedproxy.google.com/~r/Falldog/~3/PvO0K9yQqFk/win32-api-string-conversion.html</link><author>noreply@blogger.com (Falldog)</author><thr:total>0</thr:total><feedburner:origLink>http://falldog7.blogspot.com/2009/12/win32-api-string-conversion.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5817647334262996203.post-7570095310431611169</guid><pubDate>Wed, 28 Oct 2009 06:20:00 +0000</pubDate><atom:updated>2011-04-07T15:40:39.551+08:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Python</category><title>[Python] 對以Dictionary or Class為item的List做Sort</title><description>Python中的&lt;b&gt;List&lt;/b&gt;提供了sort的function，所以可以輕易地對以基本type為item( ex: [5,1,2,6,7] )的List做sort。但是如果List裡的item是&lt;span style="color: #cc0000;"&gt;Dictionary&lt;/span&gt;或是&lt;span style="color: #cc0000;"&gt;Class&lt;/span&gt; type，該如何做sort!?&lt;br /&gt;
&lt;br /&gt;
sort的definition為 &lt;b&gt;sort(&lt;/b&gt;&lt;i&gt; [&lt;span style="color: #b45f06;"&gt;cmp &lt;/span&gt;[, &lt;span style="color: #b45f06;"&gt;key &lt;/span&gt;[, &lt;span style="color: #b45f06;"&gt;reverse &lt;/span&gt;] ] ] &lt;/i&gt;&lt;b&gt;)&lt;/b&gt;&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&lt;b&gt;cmp &lt;/b&gt;: User可指定compare的function&lt;/li&gt;
&lt;li&gt;&lt;b&gt;key &lt;/b&gt;: User可指定compare的key function&lt;/li&gt;
&lt;li&gt;&lt;b&gt;reverse&lt;/b&gt;: reverse sort&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
對Dictionary type做sort&lt;br /&gt;
以下為範例 &lt;br /&gt;
&lt;pre class="prettyprint"&gt;d= [ {'id':0, 'value':9}, {'id':1, 'value':100}, {'id':5, 'value':99}, {'id':3, 'value':19}, {'id':2, 'value':59} ]
d.sort(key=lambda x:x['id']) #針對key 'id' 做sort
d.sort(key=lambda x:x['value']) #針對key 'value' 做sort

#以下用cmp，可以達到上面指定key的效果
d.sort(cmp=lambda x,y: cmp(x['id'], y['id']))
d.sort(cmp=lambda x,y: cmp(x['value'], y['value']))
&lt;/pre&gt;&lt;br /&gt;
&lt;br /&gt;
對Class type做sort&lt;br /&gt;
以下為範例 &lt;br /&gt;
&lt;pre class="prettyprint"&gt;class data:
    def __init__(self, _id, _value):
        self.id    = _id
        self.value = _value
c = [ data(0,9), data(1,100), data(5,99), data(3,19), data(2,59) ]
c.sort(key=lambda x:x.id)#針對class member id 做sort
c.sort(key=lambda x:x.value)#針對class member value 做sort

#以下用cmp，可以達到上面指定key的效果
c.sort(cmp=lambda x,y: cmp(x.id, y.id) )
c.sort(cmp=lambda x,y: cmp(x.value, y.value))
&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5817647334262996203-7570095310431611169?l=falldog7.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://feedproxy.google.com/~r/Falldog/~3/88Jo-9VWxVY/python-dictionary-or-classitemlistsort.html</link><author>noreply@blogger.com (Falldog)</author><thr:total>0</thr:total><feedburner:origLink>http://falldog7.blogspot.com/2009/10/python-dictionary-or-classitemlistsort.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5817647334262996203.post-2650923128717753796</guid><pubDate>Sun, 16 Aug 2009 01:19:00 +0000</pubDate><atom:updated>2011-04-07T09:48:49.964+08:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Chickenfoot</category><category domain="http://www.blogger.com/atom/ns#">emomeDDSMS</category><title>[emomeDDSMS] 下載emome上的備份簡訊</title><description>由於個人需求，想把過去emome上傳送的簡訊備份下來，所以寫了這個小程式。&lt;br /&gt;
&lt;br /&gt;
這個程式使用了&lt;span style="color: #cc9933; font-weight: bold;"&gt;Chickenfoot&lt;/span&gt;的API，所以只能在Firefox平台上使用時，且必須先安裝Chickenfoot套件才行。&lt;br /&gt;
Chickenfoot其實就是個在Firefox上，可即時運行script檔的套件，所以使用了Chickentfoot的API再加上了一些Javascript的程式，整個功能瞬時就變得很強大了，可以想對網頁做什麼就做什麼！(很厲害，但是也還沒到無敵啦XD)。簡單來說，就是執行Chickenfoot後，可以代替你的滑鼠+鍵盤處理一些重複的動作。也是之前同事告訴我可以用這個來自動接收開心農場的禮物，很方便滴。(中了開心農場的毒了Orz...)&lt;br /&gt;
&lt;br /&gt;
只是，Chickenfoot只是針對目前的網頁結果作處理而已，如果網頁大改版的話，程式可能也要大改版了.... XD&lt;br /&gt;
&lt;br /&gt;
環境：&lt;br /&gt;
由於Chickenfoot尚未支援Firefox 4, 所以請安裝Firefox 3.6的版本&lt;br /&gt;
個人平台為Firefox 3.6.1，測試正常&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
執行步驟：&lt;br /&gt;
1. 下載&lt;a href="http://www.cs.nctu.edu.tw/~skshie/software/emomeDDSMS/emomeDDSMS.0.7.js"&gt;emomeDDSMS.js&lt;/a&gt; (version: 0.7)&lt;br /&gt;
2. 在Firefox上安裝&lt;a href="http://groups.csail.mit.edu/uid/chickenfoot/index.php"&gt;Chickenfoot&lt;/a&gt;套件&lt;br /&gt;
3. 按&lt;span style="color: #cc9933; font-weight: bold;"&gt;F8&lt;/span&gt;，開啟Chickenfoot視窗 (會出現在左手邊 )&lt;br /&gt;
4. 按&lt;span style="color: #cc9933; font-weight: bold;"&gt;Open&lt;/span&gt;鍵，開啟舊檔，點選下載好的emomeDDSMS.js&lt;br /&gt;
5. 修改emomeDDSMS裡面的&lt;span style="font-style: italic;"&gt;參數&lt;/span&gt;(包括：帳號，密碼，輸出檔案路徑，從最新/最舊的開始下載)&lt;br /&gt;
5. 按&lt;span style="color: #009900; font-weight: bold;"&gt;綠色&lt;/span&gt;的執行鍵，開始執行！&lt;br /&gt;
&lt;br /&gt;
&lt;a href="http://3.bp.blogspot.com/_azUech_ubi0/SogfiOSU_7I/AAAAAAAAAV0/H9O9HIcNvPE/s1600-h/emomeddsms.JPG" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"&gt;&lt;img alt="" border="0" id="BLOGGER_PHOTO_ID_5370577228450299826" src="http://3.bp.blogspot.com/_azUech_ubi0/SogfiOSU_7I/AAAAAAAAAV0/H9O9HIcNvPE/s320/emomeddsms.JPG" style="cursor: pointer; display: block; height: 283px; margin: 0px auto 10px; text-align: center; width: 320px;" /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
版本更新：&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&lt;a href="http://falldog7.blogspot.com/2010/03/emomeddsms-emome-071.html"&gt;emomeDDSMS.js 0.71&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://falldog7.blogspot.com/2010/09/emomeddsms-emome-072.html"&gt;emomeDDSMS.js 0.72&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://falldog7.blogspot.com/2010/12/emomeddsms-emome-073.html"&gt;emomeDDSMS.js 0.73&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5817647334262996203-2650923128717753796?l=falldog7.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://feedproxy.google.com/~r/Falldog/~3/X4Ks3MFrSO8/emomeddsms-emome.html</link><author>noreply@blogger.com (Falldog)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/_azUech_ubi0/SogfiOSU_7I/AAAAAAAAAV0/H9O9HIcNvPE/s72-c/emomeddsms.JPG" height="72" width="72" /><thr:total>9</thr:total><feedburner:origLink>http://falldog7.blogspot.com/2009/08/emomeddsms-emome.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5817647334262996203.post-3974826795903360841</guid><pubDate>Thu, 09 Jul 2009 02:03:00 +0000</pubDate><atom:updated>2011-08-23T11:59:46.076+08:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Python</category><title>[Python] range() 與 xrange()的比較</title><description>在Python中提供了&lt;span style="color: #cc9933; font-style: italic;"&gt;range&lt;/span&gt;() function，可以建立出一個數字 list 。&lt;br /&gt;
Ex:&lt;br /&gt;
&lt;pre class="prettyprint"&gt;range(1, 10)
#&amp;gt;&amp;gt;&amp;gt; [1, 2, 3, 4, 5, 6, 7, 8, 9]

range(1, 10, 2)
#&amp;gt;&amp;gt;&amp;gt; [1,  3, 5, 7, 9]
&lt;/pre&gt;&lt;br /&gt;
而且range() 可以拿到for loop使用，因為return的值是一個 list，所以是可以被for loop接受的參數。&lt;br /&gt;
Ex:&lt;br /&gt;
&lt;pre class="prettyprint"&gt;for i in range(1, 10)
    print i,
#&amp;gt;&amp;gt;&amp;gt; 1 2 3 4 5 6 7 8 9
&lt;/pre&gt;&lt;br /&gt;
但是Python又提供了另一個&lt;span style="color: #cc9933; font-style: italic;"&gt; xrange&lt;/span&gt;() 的function，不過它return的值&lt;span style="font-style: italic;"&gt;並非&lt;/span&gt;一個list，而是類似generator的物件，而且只適用於loop (因為不是list嘛~)。&lt;br /&gt;
所以xrange跟range最大的差別就是：&lt;br /&gt;
&lt;span style="font-weight: bold;"&gt;1. &lt;/span&gt;&lt;span style="color: #cc9933; font-style: italic; font-weight: bold;"&gt;range &lt;/span&gt;&lt;span style="font-weight: bold;"&gt;是全部產生完後，return一個 list 回來使用。&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-weight: bold;"&gt;2. &lt;/span&gt;&lt;span style="color: #cc9933; font-style: italic; font-weight: bold;"&gt;xrange &lt;/span&gt;&lt;span style="font-weight: bold;"&gt;是一次產生一個值，並return一個值回來，所以xrange只適用於loop。&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
所以在&lt;span style="font-weight: bold;"&gt;效能&lt;/span&gt;上，處理完一次的 loop 後，range 跟 xrange 是差不多的，但是如果 loop 裡面有&lt;span style="color: #990000; font-weight: bold;"&gt;break &lt;/span&gt;的機會，那麼，使用 xrange 是會比較省時的。如果一定要跑完全部的 loop 的話，用range 應該是比較好的。&lt;br /&gt;
&lt;br /&gt;
Ex:&lt;br /&gt;
&lt;pre class="prettyprint"&gt;for i in range(1, 10) :
    print i,
#&amp;gt;&amp;gt;&amp;gt; 1 2 3 4 5 6 7 8 9

for i in xrange(1, 10):
    if i == 5 :
        break
    print i,
#&amp;gt;&amp;gt;&amp;gt; 1 2 3 4
&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5817647334262996203-3974826795903360841?l=falldog7.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://feedproxy.google.com/~r/Falldog/~3/x0VNo-YrWqI/python-range-xrange.html</link><author>noreply@blogger.com (Falldog)</author><thr:total>2</thr:total><feedburner:origLink>http://falldog7.blogspot.com/2009/07/python-range-xrange.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5817647334262996203.post-1252623712859363653</guid><pubDate>Wed, 08 Jul 2009 02:36:00 +0000</pubDate><atom:updated>2009-07-08T11:18:25.252+08:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">C/C++</category><title>[C/C++] switch中的case中，放變數宣告會錯!?</title><description>相信很多寫C/C++的人一定有這樣的經驗，就是在switch的case中寫入變數的宣告，結果compile卻不會過，一定會覺得很莫名奇妙，而且錯誤訊息千奇百怪...&lt;br /&gt;&lt;br /&gt;其實，是可以在switch裡的case中宣告變數的，只是要記得在前後加上 &lt;span style="color: rgb(255, 0, 0); font-weight: bold; font-style: italic;"&gt;{&lt;/span&gt;&lt;span style="font-weight: bold; font-style: italic; color: rgb(204, 153, 51);"&gt; ...&lt;/span&gt;&lt;span style="color: rgb(255, 0, 0); font-weight: bold; font-style: italic;"&gt;&lt;span style="color: rgb(204, 153, 51);"&gt; &lt;/span&gt;}&lt;/span&gt;&lt;br /&gt;Ex:&lt;br /&gt;&lt;pre class="prettyprint"&gt;switch( type )&lt;br /&gt;{&lt;br /&gt; case TYPE1:&lt;br /&gt; {&lt;br /&gt;     int t = 5;&lt;br /&gt;     printf( "%d", t );&lt;br /&gt;     break;&lt;br /&gt; }&lt;br /&gt; default:&lt;br /&gt;     break;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;以後寫switch要養成良好的習慣，自動加上{ }，不然這種error還滿難抓的。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5817647334262996203-1252623712859363653?l=falldog7.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://feedproxy.google.com/~r/Falldog/~3/uHAgubG3p7c/cc-switchcase.html</link><author>noreply@blogger.com (Falldog)</author><thr:total>0</thr:total><feedburner:origLink>http://falldog7.blogspot.com/2009/07/cc-switchcase.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5817647334262996203.post-3906954208425678180</guid><pubDate>Tue, 07 Jul 2009 08:36:00 +0000</pubDate><atom:updated>2009-10-27T14:30:20.098+08:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Python</category><title>[Python] lambda簡介</title><description>Python提供了一個簡易的function define：lambda，用完即丟，不著痕跡。讓你實作出很簡單的function(只處理一個運算式)。&lt;br /&gt;
&lt;pre class="prettyprint"&gt;lambda param1, param2, ... : expression

#其實就等於

def fun( param1, param2, ... ) :
    return expression
&lt;/pre&gt;&lt;br /&gt;
其中的expression不能放assignment，也就是這一行指令不能放=等號。因為，它就這麼簡單，別把它搞複雜化嘛~&lt;br /&gt;
&lt;br /&gt;
Ex:&lt;br /&gt;
&lt;pre class="prettyprint"&gt;def func(x, y, z):
    return x + y + z
#&amp;gt;&amp;gt;&amp;gt;  func(1, 2, 3)
#&amp;gt;&amp;gt;&amp;gt;  6

func2 = lambda x,y,z : x+y+z
#&amp;gt;&amp;gt;&amp;gt;  func2(1, 2, 3)
#&amp;gt;&amp;gt;&amp;gt;  6

#也可以應用在map上
my_list = [1, 2, 3]
map( lambda i: i * i, my_list )
#&amp;gt;&amp;gt;&amp;gt;  (1, 4, 9)
&lt;/pre&gt;&lt;br /&gt;
lambda在某些方面而言確實是很好用，但是也不能濫用，否則可能造成程式的可讀性降低。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5817647334262996203-3906954208425678180?l=falldog7.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://feedproxy.google.com/~r/Falldog/~3/3KTwq9jFXBc/python-lambda.html</link><author>noreply@blogger.com (Falldog)</author><thr:total>0</thr:total><feedburner:origLink>http://falldog7.blogspot.com/2009/07/python-lambda.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5817647334262996203.post-197401124840611696</guid><pubDate>Fri, 03 Jul 2009 07:18:00 +0000</pubDate><atom:updated>2011-08-23T12:00:45.561+08:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Python</category><title>[Python] swap</title><description>由於Python裡的變數只有reference的概念，所以function也沒有分什麼call by value, call by reference。所以，一般C/C++的寫法是不work的。&lt;br /&gt;
&lt;pre class="prettyprint"&gt;def swap( a, b ):
    t = a
    a = b
    b = t

#&amp;gt;&amp;gt;&amp;gt; a = 1
#&amp;gt;&amp;gt;&amp;gt; b = 2
#&amp;gt;&amp;gt;&amp;gt; swap( a, b)
#&amp;gt;&amp;gt;&amp;gt; a,b
#&amp;gt;&amp;gt;&amp;gt; (1,2)  # 沒變
&lt;/pre&gt;&lt;br /&gt;
要怎麼樣才能讓兩個變數做swap的動作呢？其實很簡單：&lt;br /&gt;
&lt;pre class="prettyprint"&gt;a = 1
b = 2
a, b = b, a
#&amp;gt;&amp;gt;&amp;gt; a, b
#&amp;gt;&amp;gt;&amp;gt; (2,1)&lt;/pre&gt;&lt;br /&gt;
這樣就可以了，夠easy了吧，因為Python會先將右邊的b,a create成一個新的tuple變數，然後再assign給左邊原本的變數a跟b。&lt;br /&gt;
&lt;br /&gt;
要把它寫成function也行：&lt;br /&gt;
&lt;pre class="prettyprint"&gt;def swap( a, b ):
    return b, a&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5817647334262996203-197401124840611696?l=falldog7.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://feedproxy.google.com/~r/Falldog/~3/_b4k6nPjgME/python-swap.html</link><author>noreply@blogger.com (Falldog)</author><thr:total>2</thr:total><feedburner:origLink>http://falldog7.blogspot.com/2009/07/python-swap.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5817647334262996203.post-7735865741207334234</guid><pubDate>Sat, 02 May 2009 04:01:00 +0000</pubDate><atom:updated>2009-05-02T12:09:45.581+08:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Delphi</category><category domain="http://www.blogger.com/atom/ns#">BCB</category><category domain="http://www.blogger.com/atom/ns#">電子書</category><title>C++ Builder / Delphi 深度歷險 電子書下載</title><description>上次貼出侯捷大師的&lt;a href="http://falldog7.blogspot.com/2009/01/mfc-2e.html"&gt;「深入淺出MFC」&lt;/a&gt;電子書下載連結，獲得不少好評，心胸寬大的作者不只侯捷一人，還有陳昇瑋大師的著作C++ Builder 深度歷險、Delphi 深度歷險這兩本書也有免費的電子書可以下載，有興趣的人可以下載來閱讀。(感謝Beavis大大的推薦)&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.iis.sinica.edu.tw/%7Eswc/index_c.html"&gt;陳昇瑋大師的個人網頁&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.iis.sinica.edu.tw/%7Eswc/book/delphi_adv.pdf"&gt;Delphi 深度歷險 電子書下載連結&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.iis.sinica.edu.tw/%7Eswc/book/bcb_adv.pdf"&gt;C++ Builder 深度歷險 電子書下載連結&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5817647334262996203-7735865741207334234?l=falldog7.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://feedproxy.google.com/~r/Falldog/~3/GP2cMZdboMo/c-builder-delphi.html</link><author>noreply@blogger.com (Falldog)</author><thr:total>2</thr:total><feedburner:origLink>http://falldog7.blogspot.com/2009/05/c-builder-delphi.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5817647334262996203.post-4503846771967594744</guid><pubDate>Sat, 31 Jan 2009 00:57:00 +0000</pubDate><atom:updated>2009-02-25T23:42:50.453+08:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Python</category><category domain="http://www.blogger.com/atom/ns#">Skype API</category><title>初探Skype4Py</title><description>　　在Skype API裡，除了之前介紹的Windows Message、Skype4Com的方法之外，還有一個Skype4Py可以使用。&lt;br /&gt;&lt;br /&gt;　　Skype4Py是用Python的語法，將Skype API包裝起來，提供一層high-level的介面供使用者使用，用法跟Skype4Com很類似，而且它還有一個特點，就是&lt;span style="font-weight: bold;"&gt;跨平台&lt;/span&gt;！寫出一個Skype4Py的Python程式，可以在Wiindows、Linux和Mac等不同的OS上執行。而這也是Python的特點之一。&lt;br /&gt;&lt;br /&gt;　　在我看過Skype4Py的source code後，原來它只是將不同平台上的Skype API底層的做法包裝起來，所以實際上它執行的方法，在Windows上，還是透過Windows Message傳遞的。有興趣的人可以參考看看。&lt;br /&gt;&lt;br /&gt;安裝方法：&lt;br /&gt;&lt;ol&gt;&lt;li&gt;安裝&lt;a href="http://python.org/download/"&gt;Python&lt;/a&gt; 2.4以上的版本&lt;/li&gt;&lt;li&gt;安裝&lt;a href="http://skype.com/go/downloading"&gt;Skype&lt;/a&gt;&lt;/li&gt;&lt;li&gt;安裝&lt;a href="http://sourceforge.net/project/showfiles.php?group_id=202148"&gt;Skype4Py&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;　　就是這麼簡單，在安裝Skype4Py上，也提供了多種選則，在Windows上可以安裝exe執行檔，或是下載source code自行下指令安裝。&lt;br /&gt;&lt;br /&gt;　　在安裝完成後，就可以寫個小小的簡單測試程式：&lt;br /&gt;&lt;pre class="prettyprint"&gt;import Skype4Py&lt;br /&gt;&lt;br /&gt;# Create Skype instance&lt;br /&gt;skype = Skype4Py.Skype()&lt;br /&gt;&lt;br /&gt;# Connect Skype object to Skype client&lt;br /&gt;skype.Attach()&lt;br /&gt;&lt;br /&gt;print 'Your full name:', skype.CurrentUser.FullName&lt;br /&gt;print 'Your contacts:'&lt;br /&gt;for user in skype.Friends:&lt;br /&gt;    print '    ', user.FullName&lt;/pre&gt;　　寫法相當的簡潔，這樣子就可以取得好友清單了。Skype4Py的另一項特點，就是它的&lt;a href="http://skype4py.sourceforge.net/doc/html/"&gt;線上Document&lt;/a&gt;格式長得很像JavaDoc的格式，個人覺得在使用上是頗為方便。&lt;br /&gt;&lt;br /&gt;相關網頁：&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="https://developer.skype.com/wiki/Skype4Py"&gt;Skype4Py首頁&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://sourceforge.net/project/showfiles.php?group_id=202148"&gt;Skype4Py Sourceforge.Net下載首頁&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://developer.skype.com/wiki/Skype4Py/installation"&gt;安裝說明&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://skype4py.sourceforge.net/doc/html/"&gt;Skype4Py使用說明 (Document)&lt;br /&gt;&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://developer.skype.com/wiki/Skype4Py/examples"&gt;Skype4Py Example&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5817647334262996203-4503846771967594744?l=falldog7.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://feedproxy.google.com/~r/Falldog/~3/USnBJQiOSoQ/skype4py.html</link><author>noreply@blogger.com (Falldog)</author><thr:total>1</thr:total><feedburner:origLink>http://falldog7.blogspot.com/2009/01/skype4py.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5817647334262996203.post-1600594554439099397</guid><pubDate>Thu, 29 Jan 2009 15:53:00 +0000</pubDate><atom:updated>2009-01-30T00:12:18.997+08:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Skype API</category><title>Skype API - DTMF介紹</title><description>&lt;p&gt;　　在一般的電話對談中，如果我們不小心按到了電話上的按鍵(0~9, #, *)，此時會響起一個嗶嗶聲，這個聲響就是以DTMF的方式編碼傳送，每個按鍵都有各自獨有的頻率，所以照理來說，只要對方可以解析傳來的DTMF頻率，即可知道傳來的按鍵為何，可以讓對方做進一步的處理…(如，撥打分機號碼)&lt;br /&gt;&lt;/p&gt;&lt;p&gt;　　而在Skype的AP中，也有著類似的介面供使用者在通話中，按下畫面上虛擬的按鍵，即會發出DTMF Tone了。而 Skype API 也有提供解析DTMF code的方法，很是方便。&lt;/p&gt;&lt;strong&gt;&lt;em&gt;　　Skype API&lt;/em&gt;&lt;/strong&gt; 提供了一個Command供使用者送出/接收DTMF code，「&lt;strong&gt;&lt;span style="color: rgb(255, 128, 64);"&gt;SET CALL DTMF&lt;/span&gt;&lt;/strong&gt;」，在&lt;strong&gt;&lt;em&gt;Skype4Com&lt;/em&gt;&lt;/strong&gt;裡，也提供了一個Event，當收到DTMF code時，就會觸發「&lt;strong&gt;&lt;span style="color: rgb(255, 128, 64);"&gt;CallDtmfReceived&lt;/span&gt;&lt;/strong&gt;」Event，不過在使用上還是有些限制…&lt;br /&gt;&lt;ol&gt;&lt;li&gt;使用者只能接收到&lt;strong&gt;對方&lt;/strong&gt;送來的DTMF code。當自己送出DTMF code時，並&lt;strong&gt;不會&lt;/strong&gt;觸發CallDtmfReceived Event。&lt;br /&gt;&lt;/li&gt;&lt;li&gt;在Skype4Com的Document中提到，「&lt;em&gt;This event can be received with P2P calls&lt;/em&gt;」，所以似乎只限定在P2P的通話上( Skype AP&amp;lt;-&amp;gt;Skype AP )，&lt;strong&gt;不支援手機&lt;/strong&gt;&lt;span style="font-weight: bold;"&gt;&amp;lt;-&amp;gt;&lt;/span&gt;&lt;strong&gt;Skype AP&lt;/strong&gt;。&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;&lt;strong&gt;範例程式：&lt;br /&gt;&lt;/strong&gt;&lt;a href="http://www.cs.nctu.edu.tw/%7Eskshie/Blogger/Skype/prjexample_Skype4Com_DTMF.rar" target="_blank"&gt;範例程式下載連結&lt;/a&gt; &lt;/p&gt;&lt;pre class="prettyprint"&gt;#include &amp;lt;vcl.h&amp;gt;&lt;br /&gt;#include &amp;lt;iostream&amp;gt;&lt;br /&gt;#pragma hdrstop&lt;br /&gt;&lt;br /&gt;#include "Unit1.h"&lt;br /&gt;//---------------------------------------------------------------------------&lt;br /&gt;#pragma package(smart_init)&lt;br /&gt;#pragma link "SKYPE4COMLib_OCX"&lt;br /&gt;#pragma resource "*.dfm"&lt;br /&gt;TForm1 *Form1;&lt;br /&gt;using namespace std;&lt;br /&gt;&lt;br /&gt;// 這個程式是用來測試Skype4Com的一些功能&lt;br /&gt;// (1) 要執行這個程式 首先要將$(BCB)/Imports/加入 Include Path&lt;br /&gt;//    #include "SKYPE4COMLib_OCX.h"&lt;br /&gt;// (2) 需要新增以下的元件：&lt;br /&gt;//    TListBox *ListBox1;&lt;br /&gt;//    TMemo *Memo1;&lt;br /&gt;// (3) 需要額外宣告變數：&lt;br /&gt;//    TSkype * mSkype;&lt;br /&gt;&lt;br /&gt;//---------------------------------------------------------------------------&lt;br /&gt;__fastcall TForm1::TForm1(TComponent* Owner)&lt;br /&gt;      : TForm(Owner)&lt;br /&gt;{&lt;br /&gt;      mSkype = new TSkype(Owner);&lt;br /&gt;      mSkype-&amp;gt;Attach(5,false);&lt;br /&gt;  &lt;br /&gt;      // test if Skype is running, if not, start it;&lt;br /&gt;      if( !mSkype-&amp;gt;Client-&amp;gt;IsRunning )&lt;br /&gt;          mSkype-&amp;gt;Client-&amp;gt;Start(false,false);&lt;br /&gt;          // 1st parameter - start Skype in minimized state&lt;br /&gt;          // 2nd parameter - show splash screen&lt;br /&gt;    &lt;br /&gt;      // Get the count of Friends&lt;br /&gt;      int count = mSkype-&amp;gt;Friends-&amp;gt;get_Count();&lt;br /&gt;&lt;br /&gt;      // Add Friend list to Memo&lt;br /&gt;      for( int i=1 ; i&amp;lt;count ; i++ )// start index from 1 !!!&lt;br /&gt;          this-&amp;gt;ListBox1-&amp;gt;Items-&amp;gt;Add( mSkype-&amp;gt;Friends-&amp;gt;get_Item(i)-&amp;gt;get_Handle() );&lt;br /&gt;&lt;br /&gt;      // bind the Skype Event.&lt;br /&gt;      mSkype-&amp;gt;OnCallDtmfReceived = OnCallDtmfReceived;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;// Skype4Com的Event&lt;br /&gt;// 在Skype4Com.chm中定義的 Class : _SkypeEvents 裡面&lt;br /&gt;// HRESULT  CallDtmfReceived ([in] ICall *pCall,[in] BSTR Code)&lt;br /&gt;//  This event is caused by a call DTMF event.&lt;br /&gt;// 經由BCB處理過後的header檔，定義在 $(BCB)/Imports/SKYPE4COMLib_OCX.h 100行&lt;br /&gt;//&lt;br /&gt;// @target : when receive the DTMF code, print on Memo.&lt;br /&gt;void __fastcall TForm1::OnCallDtmfReceived( TObject *Sender, ICall* pCall/*[in]*/, BSTR code/*[in]*/)&lt;br /&gt;{&lt;br /&gt;      this-&amp;gt;Memo1-&amp;gt;Lines-&amp;gt;Add( "OnCallDtmfReceived" );&lt;br /&gt;      if( pCall!=NULL ){&lt;br /&gt;          this-&amp;gt;Memo1-&amp;gt;Lines-&amp;gt;Add( AnsiString("DTMF Code : ")+WideString(code) );&lt;br /&gt;      }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;補充：&lt;br /&gt;&lt;/strong&gt;在coding時的測試要透過兩個不同的Skype AP，一般的情況下都得在兩台安裝Skype AP的電腦上測試，建議可以用官網提供的&lt;a href="http://forum.skype.com/index.php?showtopic=88055" target="_blank"&gt;Skype Launcher&lt;/a&gt;這個小程式，就能在一台電腦上執行多個Skype AP了。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;相關連結：&lt;/strong&gt;&lt;br /&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://forum.skype.com/index.php?showtopic=88055" target="_blank"&gt;Skype Launcher&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://developer.skype.com/Docs/ApiDoc/SET_CALL_DTMF" target="_blank"&gt;Skype API – SET CALL DTMF&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.cs.nctu.edu.tw/%7Eskshie/Blogger/Skype/prjexample_Skype4Com_DTMF.rar" target="_blank"&gt;範例程式下載連結&lt;/a&gt; &lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5817647334262996203-1600594554439099397?l=falldog7.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://feedproxy.google.com/~r/Falldog/~3/NMFDPHDCOq0/skype-api-dtmf.html</link><author>noreply@blogger.com (Falldog)</author><thr:total>0</thr:total><feedburner:origLink>http://falldog7.blogspot.com/2009/01/skype-api-dtmf.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5817647334262996203.post-5358501802917117726</guid><pubDate>Sat, 17 Jan 2009 05:51:00 +0000</pubDate><atom:updated>2009-01-17T13:52:08.287+08:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Python</category><title>[Python] 實作出 class中的 virtual function</title><description>&lt;p&gt; 　　在Python的世界裡，Class並沒有pure virtual function的概念，所以也沒有所謂的virtual class，但是實際上Python提供了一套機制去模擬virtual function的概念，雖然不像C++&lt;em&gt;嚴謹&lt;/em&gt;到無法使用virtual class去宣告出一個實體物件，但是至少在使用此function時，可以丟出一個Error Message出來。&lt;/p&gt;  &lt;p&gt; 　　Python提供的方法就是，你可以在pure virtual function裡，丟一個Error message &lt;span style="color:#ff0000;"&gt;&lt;strong&gt;NotImplementedError&lt;/strong&gt;&lt;/span&gt;出來，夠簡單了吧… 其實自己隨便丟一個也可以達到相同的目的=_=，只是Python提供了個error type，讓我們用起來更有感覺。不過，沒魚蝦也好啦~&lt;/p&gt;  &lt;p&gt;以下是範例程式碼…&lt;/p&gt;  &lt;pre class="prettyprint"&gt;class virtualClass:&lt;br /&gt;   def __init__(self):&lt;br /&gt;       pass&lt;br /&gt;   def virtualMethod(self): #virtual function.&lt;br /&gt;       raise NotImplementedError( "virtualMethod is virutal! Must be overwrited." )&lt;br /&gt;&lt;br /&gt;class subClass( virtualClass ):&lt;br /&gt;   def __init__(self):&lt;br /&gt;       virtualClass.__init__(self)&lt;br /&gt;       pass&lt;br /&gt;   def virtualMethod(self): #overwrite the virtual function.&lt;br /&gt;       print 'subClass! have overwirted the virtualMethod() success.'&lt;br /&gt;&lt;br /&gt;v = virtualClass()&lt;br /&gt;v.virtualMethod()&lt;br /&gt;&lt;br /&gt;s = subClass()&lt;br /&gt;s.virtualMethod()&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5817647334262996203-5358501802917117726?l=falldog7.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://feedproxy.google.com/~r/Falldog/~3/1J9GgZ-JLRs/python-class-virtual-function.html</link><author>noreply@blogger.com (Falldog)</author><thr:total>1</thr:total><feedburner:origLink>http://falldog7.blogspot.com/2009/01/python-class-virtual-function.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5817647334262996203.post-1654965632466514625</guid><pubDate>Fri, 16 Jan 2009 17:42:00 +0000</pubDate><atom:updated>2011-04-23T23:29:06.346+08:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">MFC</category><category domain="http://www.blogger.com/atom/ns#">電子書</category><title>侯捷大師 - 深入淺出MFC 2/e 電子書下載</title><description>最近想看看MFC的書，也不知道什麼書寫得比較好，就搜尋一下別人推薦的，結果就找到這個免費的電子書，而且是全書的章節都有，侯捷大師真是佛心來著的(大心)。真的是太屌了，我只能這麼說，一個作者可以完全開放電子書供人下載，胸襟之大，可以見得。&lt;br /&gt;
&lt;br /&gt;
有興趣的人也可以下載來看看，是繁體中文版的喔~&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&lt;a href="http://jjhou.boolan.com/"&gt;侯捷大師網站&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://jjhou.boolan.com/free-u002p.htm"&gt;原始下載網頁&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
直接下載PDF檔連結：&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&lt;a href="http://jjhou.boolan.com/dissecting%20MFC%202e%20part1.pdf"&gt;深入淺出MFC 2/e - part1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://jjhou.boolan.com/dissecting%20MFC%202e%20part2.pdf"&gt;深入淺出MFC 2/e - part2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://jjhou.boolan.com/dissecting%20MFC%202e%20part3.pdf"&gt;深入淺出MFC 2/e - part3&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://jjhou.boolan.com/dissecting%20MFC%202e%20part4.pdf"&gt;深入淺出MFC 2/e - part4&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://jjhou.boolan.com/dissecting%20MFC%202e%20part5.pdf"&gt;深入淺出MFC 2/e - part5&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5817647334262996203-1654965632466514625?l=falldog7.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://feedproxy.google.com/~r/Falldog/~3/0HA8GnECDw4/mfc-2e.html</link><author>noreply@blogger.com (Falldog)</author><thr:total>4</thr:total><feedburner:origLink>http://falldog7.blogspot.com/2009/01/mfc-2e.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5817647334262996203.post-801314419704526904</guid><pubDate>Sun, 04 Jan 2009 14:51:00 +0000</pubDate><atom:updated>2009-01-05T00:05:02.175+08:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Skype API</category><title>做中學 - Skype API Tracer</title><description>第一次接觸Skype API的人，看完上一篇介紹&lt;a href="http://falldog7.blogspot.com/2007/10/skype-api.html"&gt;Skype API架構&lt;/a&gt;的文章後，可能還是霧煞煞的，不太清楚在講什麼東東，沒關係，在這邊我們可以藉由一個Skype官網提供的 Tool - &lt;span style="font-weight: bold; font-style: italic;"&gt;Skype API Tracer &lt;/span&gt;的幫忙，來更加了解Skype API到底在搞什麼 、怎麼搞的!?&lt;br /&gt;&lt;br /&gt;首先，必須先到 &lt;a href="https://developer.skype.com/Download"&gt;Skype Download&lt;/a&gt; 頁面下載 &lt;a href="https://developer.skype.com/Download?action=AttachFile&amp;amp;do=get&amp;amp;target=Tracer.exe"&gt;Skype API Tracer&lt;/a&gt; 這個 Tool。&lt;br /&gt;&lt;br /&gt;接著，開啟你電腦上的Skype，並啟動 &lt;span style="font-weight: bold;"&gt;Skype API Tracer&lt;/span&gt;，操作介面如下：&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_azUech_ubi0/SWDUY2775II/AAAAAAAAAR0/f_wlMBNPos8/s1600-h/Tracer.JPG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 268px; height: 209px;" src="http://1.bp.blogspot.com/_azUech_ubi0/SWDUY2775II/AAAAAAAAAR0/f_wlMBNPos8/s320/Tracer.JPG" alt="" id="BLOGGER_PHOTO_ID_5287459486061814914" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;操作介面非常的簡潔明瞭，這個Tool就是透過Skype API去操控原本的Skype主程式，比如，在指令輸入欄位輸入「&lt;span style="font-weight: bold; color: rgb(204, 153, 51);"&gt;PING&lt;/span&gt;」後，就會回傳「&lt;span style="font-weight: bold;"&gt;PONG&lt;/span&gt;」。&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_azUech_ubi0/SWDVL8wHBkI/AAAAAAAAAR8/80jFzFDo-GE/s1600-h/Tracer-ping.JPG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 269px; height: 210px;" src="http://1.bp.blogspot.com/_azUech_ubi0/SWDVL8wHBkI/AAAAAAAAAR8/80jFzFDo-GE/s320/Tracer-ping.JPG" alt="" id="BLOGGER_PHOTO_ID_5287460363796153922" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;也可以輸入指令，取得目前登入Skype帳號的好友清單，輸入「&lt;span style="font-weight: bold; color: rgb(204, 153, 51);"&gt;SEARCH FRIENDS&lt;/span&gt;」，接著就會回傳「&lt;span style="font-weight: bold;"&gt;USERS echo123, xxx1, xxx2, xxx3, ....&lt;/span&gt;」回傳好友清單中，每個好友的帳號的串列，並以分號「，」為間隔。&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_azUech_ubi0/SWDWOxe6qeI/AAAAAAAAASE/fdWx3FCSebw/s1600-h/Tracer-friends.JPG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 250px;" src="http://4.bp.blogspot.com/_azUech_ubi0/SWDWOxe6qeI/AAAAAAAAASE/fdWx3FCSebw/s320/Tracer-friends.JPG" alt="" id="BLOGGER_PHOTO_ID_5287461511822485986" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;當然除了取得帳號相關的資訊外，也可以針對Skype的視窗處理的API，如「&lt;span style="font-weight: bold; color: rgb(204, 153, 51);"&gt;MINIMIZE &lt;/span&gt;」，輸入後，Skype主程式的視窗就會自動最小化。輸入「&lt;span style="font-weight: bold; color: rgb(204, 153, 51);"&gt;OPEN DIALPAD&lt;/span&gt;」後會出現Skype的撥號介面。&lt;br /&gt;&lt;br /&gt;當然也可以透過指令，讓Skype撥電話給某位使用者，比如我想打電話給我的朋友SummerDog，就輸入「&lt;span style="font-weight: bold; color: rgb(204, 153, 51);"&gt;Call&lt;/span&gt;&lt;span style="color: rgb(204, 153, 51);"&gt; &lt;/span&gt;&lt;span style="font-style: italic; color: rgb(204, 153, 51);"&gt;SummerDog&lt;/span&gt;」即可，Skype會自動幫你處理接下來撥號的動作。&lt;br /&gt;&lt;br /&gt;所以，說穿了，Skype API也不過是個文字遊戲，我們丟給它一些文字指令，它可以選擇吃不吃這些指令，不吃就吐個錯誤訊息給你，吃的下去，就幫你處理一些事情，或是回傳一些有用的訊息給你。&lt;br /&gt;而這些文字訊息都必須透過Windows Message去傳遞，而且必須注意的是，文字訊息的內容，必須用&lt;span style="font-weight: bold; color: rgb(255, 102, 0);"&gt;UTF-8&lt;/span&gt;的編碼格式才行，不然文字訊息一有中文的內容，而Programmer又不將中文encoding成UTF-8的編碼(在程式裡，預設編碼應該是Big5)，Skype會完全看不懂這訊息，就不會理你了。&lt;br /&gt;&lt;br /&gt;以上介紹的這些API指令，都可以在官網找到說明與簡易教學，在這邊列出給大家參考一下：&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="https://developer.skype.com/Docs/ApiDoc/FrontPage"&gt;Skype API Command列表&lt;/a&gt;&lt;/li&gt;&lt;li&gt;指令 - &lt;a href="https://developer.skype.com/Docs/ApiDoc/SEARCH_FRIENDS"&gt;Search Friends&lt;/a&gt;&lt;/li&gt;&lt;li&gt;指令 - &lt;a href="https://developer.skype.com/Docs/ApiDoc/MINIMIZE"&gt;Minimize&lt;/a&gt;&lt;/li&gt;&lt;li&gt;指令 - &lt;a href="https://developer.skype.com/Docs/ApiDoc/OPEN_DIALPAD"&gt;Open Dialpad&lt;/a&gt;&lt;/li&gt;&lt;li&gt;指令 - &lt;a href="https://developer.skype.com/Docs/ApiDoc/CALL"&gt;Call&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;可以用的API指令還滿多的，有興趣的人，可以先使用Skype API Tracer先與Skype溝通一下後，再試著寫入程式裡面，會更有效率~&lt;br /&gt;&lt;br /&gt;以上介紹的API指令，都是屬於Windows Message傳遞去控制Skype，其實還有另一個方法，可以用Function的概念去處理Skype API的架構 - Skype4Com，有興趣的人可以參考一下&lt;a href="http://falldog7.blogspot.com/2008/01/skype-api-skype4com.html"&gt;拙作&lt;/a&gt;。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5817647334262996203-801314419704526904?l=falldog7.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://feedproxy.google.com/~r/Falldog/~3/UXOLZ4kvdIg/skype-api-tracer.html</link><author>noreply@blogger.com (Falldog)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/_azUech_ubi0/SWDUY2775II/AAAAAAAAAR0/f_wlMBNPos8/s72-c/Tracer.JPG" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://falldog7.blogspot.com/2009/01/skype-api-tracer.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5817647334262996203.post-5159821687065217977</guid><pubDate>Fri, 26 Dec 2008 12:27:00 +0000</pubDate><atom:updated>2008-12-27T08:49:19.855+08:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Python</category><title>Python IDE - HAP (Python Remote Debugger)</title><description>由於公司專案開發使用的程式語言是Python，所以不能像以前一樣只用Notepad++打天下了。進公司後才知道Python有 &lt;a style="font-weight: bold;" href="http://hapdebugger.sourceforge.net/"&gt;HAP&lt;/a&gt; (全名是&lt;span style="font-style: italic;"&gt;Python Remote Debugger&lt;/span&gt;)這個IDE的開發工具，下面是它執行的介面圖。很普通，但是基本應該有的功能都有。&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_azUech_ubi0/SVN8aS_TM8I/AAAAAAAAARU/t78-5dtx0hM/s1600-h/PyCharmer.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 230px;" src="http://2.bp.blogspot.com/_azUech_ubi0/SVN8aS_TM8I/AAAAAAAAARU/t78-5dtx0hM/s320/PyCharmer.jpg" alt="" id="BLOGGER_PHOTO_ID_5283703579051504578" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;HAP - &lt;span style="font-style: italic;"&gt;Python Remote Debugger&lt;/span&gt;具備下列幾項&lt;span style="font-weight: bold;"&gt;優點&lt;/span&gt;：&lt;br /&gt;&lt;ol&gt;&lt;li&gt;可以儲存Python專案。&lt;/li&gt;&lt;li&gt;可以設中斷點除錯，一般的除錯功能都有，包括Wath、Call Stack、Local視窗，真的還滿方便的。&lt;/li&gt;&lt;li&gt;有類似Noteped++的書籤功能，可以讓改code更方便。&lt;/li&gt;&lt;li&gt;支援Tab、Shift Tab，調整code的range。&lt;/li&gt;&lt;li&gt;支援選取多行程式，自動註解的功能。&lt;/li&gt;&lt;li&gt;自動解析py檔的Class架構，列出檔案中所有的function list。&lt;/li&gt;&lt;/ol&gt;但是也是有幾個&lt;span style="font-weight: bold;"&gt;缺點&lt;/span&gt;啦：&lt;br /&gt;&lt;ol&gt;&lt;li&gt;最新版本是2005.08的版本，已經很久沒有再更新了…&lt;/li&gt;&lt;li&gt;Only for Windows.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;預設關閉「顯示Line Number」的功能，沒有Line Number在旁邊，真的很麻煩@_@&lt;/li&gt;&lt;li&gt;程式碼的顏色沒有Template可以選擇，我個人是比較習慣黑底的介面，雖然自己改成黑底的介面，但是由於它是將設定存在Register中，所以不能像Notepad++一樣分享出來。&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;總體而言，它是目前Python IDE的首選了吧！&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;相關連結：&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://hapdebugger.sourceforge.net/"&gt;HAP 首頁&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://sourceforge.net/projects/hapdebugger/"&gt;HAP SourceForge.nt 首頁&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://sourceforge.net/project/showfiles.php?group_id=43297&amp;amp;package_id=36003"&gt;HAP 下載頁面&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://sourceforge.net/project/showfiles.php?group_id=43297&amp;amp;package_id=35575"&gt;HAP Source Code下載頁面&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5817647334262996203-5159821687065217977?l=falldog7.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://feedproxy.google.com/~r/Falldog/~3/G0o3osjwlSo/python-ide-hap-pycharmer.html</link><author>noreply@blogger.com (Falldog)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/_azUech_ubi0/SVN8aS_TM8I/AAAAAAAAARU/t78-5dtx0hM/s72-c/PyCharmer.jpg" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://falldog7.blogspot.com/2008/12/python-ide-hap-pycharmer.html</feedburner:origLink></item></channel></rss>

