2008年12月29日 星期一

Python 的時間

因為經常為 Python 處理時間的問題煩惱,所以打算留篇記錄以便之後查閱。

  • 取得今天日期


    import datetime
    today = datetime.date.today()
    # today 是一個 datetime.date object

  • 取得現在日期及時間


    import datetime
    current = datetime.datetime.now()
    # current 是一個 datetime.datetime object

  • 建立日期


    import datetime
    some_day = datetime.datetime(2008, 12, 25)

  • 建立日期及時間


    import datetime
    some_day = datetime.datetime(2008, 12, 25, 12, 0, 0)

  • 格式化現在時間


    from time import strftime
    now = strftime('%Y-%m-%d %H:%M:%S')
    # now 是一個 str, '2008-12-29 16:12:34'

  • 格式化 datetime.datetime object


    import datetime
    some_day = datetime.datetime(2008, 12, 25)
    print some_day.strftime('%Y-%m-%d')
    # 得到 '2008-12-25'

  • datetime.datetime 可以相減(算差距),也可以直接比較

  • 換成 tuple


    import datetime
    now_tuple = datetime.datetime.now().timetuple()
    # now_tuple 會得到一個 tuple

  • 取得 timestamp


    import time
    ts = time.time()
    # ts 是一個 timestamp, type 為 float

  • 從 timestamp 換回 datetime object


    import time
    import datetime
    ts = time.time()
    dt = datetime.datetime.fromtimestamp(ts)

  • 從 time tuple 換成 timestamp


    from time import mktime
    ts = mktime(now_tuple)
    # ts 是 timestamp

2008年10月12日 星期日

驗證檔案的內容

我們在很多網站下載檔案時,為了確保檔案內容沒有被修改過,通常檔案的提供者會提供你一組 MD5 或 SHA-1 之類的字串供你驗證,我把這個動作寫成一個 python script 來快速檢查:


#!/usr/bin/env python
# -*- coding: utf-8 -*-
import hashlib
import os
import sys

def usage(app_name):
"""
The usage doc
"""
return """Usage: %s _filename_ _hash_algo_ _hash_value_"""

def main(args):
"""
Main program
"""
try:
f = open(args[0], 'r')
dig = getattr(hashlib, args[1])(f.read()).hexdigest()
f.close()
print (dig == args[2] and 'Valid') or 'Invalid'
except IOError, e:
print '找不到檔案 "%s"' % args[0]
except AttributeError, e:
print 'Hash 演算法名稱錯誤'

def commandline():
if len(sys.argv) > 2:
main(sys.argv[1:])
else:
print usage(sys.argv[0])

if __name__ == '__main__':
commandline()

簡單的使用方法就是 「script 檔名 演算法 驗證碼」,如果我將這個 script 存成一個叫 verify.py 的檔案,下載了一個 foo.dat 的檔案,要用 sha1 演算法檢查 abcdefg(假的,sha-1 的碼很長),那就這樣用:

verify.py foo.dat sha1 abcdefg

演算法直接用 python hashlib 裡支援的,如果不支援就會直接跳到 AttributeError :P

2008年9月3日 星期三

根據 ID 抓取 YouTube 影片


def progress_hook(block_number, block_size, total_size):
if total_size > 0:
percentage = 100 * block_number * block_size / total_size
if percentage > 100:
percentage = 100
print '%2d%%' % percentage

def getYouTubeVideoByID(video_id, output_filename):
import re, urllib
url = 'http://www.youtube.com/v/%s' % (video_id)
real_url = urllib.urlopen(url).geturl()
match = re.findall("t=([^&]*)", real_url)
if match:
fetch_url = 'http://www.youtube.com/get_video.php?video_id=%s&t=%s' % (video_id, match[0])
print fetch_url
try:
urllib.urlretrieve(fetch_url, output_filename, progress_hook)
except urllib.ContentTooShortError:
print 'ContentTooShortError'


其中 progress_hook 是用來顯示進度的,如果不喜歡可以自己修改格式,或是在 getYouTubeVideoByID 裡面呼叫 urllib.urlretrieve 的地方把 progress_hook 這個參數拿掉。

使用方法: getYouTubeVideoByID(<id>, <file_name>)
範例:
getYouTubeVideoByID('2scOjA_U09w', 'E:\\CCF.flv')

2008年6月18日 星期三

動態改變 instance 的 member function

首先先建立一個 class:


class foo:
def say(self, s):
print 'Hello, %s' % (s)

f = foo()
f.say('Bob')

這樣會印出 'Hello, Bob'。
如果想把裡面的 say 換成自己定義的 function,可以先定義該 function:

def helloworld(self, s):
print 'Hello World %s' % (s)

然後再用 new.instancemethod 把它給換掉:

import new
f.say = new.instancemethod(helloworld, f, foo)
f.say('Alice')

這樣就會印出 'Hello Wolrd, Alice' 囉

2008年4月29日 星期二

Python 的字元編碼

Python 並不像其它語言一樣,看你的程式碼檔案是什麼字元編碼就用什麼編碼來解讀內部的字串。所以必須在檔案開頭處清楚地宣告
# -*- coding: utf-8 -*-
當然你的程式碼檔案也要存成對應的編碼才能正常執行。

而如果在一個 utf-8 編碼的程式碼裡,若要將某 utf-8 字串轉成 cp950 (在 Windows 上蠻常用的)的話,只要:

str = "我是UTF-8的字串"
print str.decode('utf-8').encode('cp950')

就可以了。相當方便!

Python 版的 switch case

其實一直不太清楚為什麼 Python 內建的語法會沒有 switch/case 的用法,所以這時候只好自己做一下了

如果本來在 C 裡會寫這樣:

x = 0;
switch (value) {
case 1:
x += 1;
break;
case 2:
x *= 5;
break;
...
}

那在 Python 裡可以寫成這樣:
x  = 0
{
1: lambda y: y += 1,
2: lambda y: y *= 5
...
}[value](x)


簡單地說就是用 dictionary 來作。

2008年4月24日 星期四

簡易密碼產生器



2008年1月26日 星期六

在 Mac 上編譯 Python 3 的問題

Python 3 (a.k.a. Py3k) 目前已經推出 3.0a2 的版本,我拿到 Mac 系統上編譯時,下的參數為:

./configure --prefix=/usr/local --enable-framework --enable-toolbox-glue --with-threads

結果在編譯時會出現這樣的錯誤:
LookupError: unknown encoding: X-MAC-TRAD-CHINESE

看起來是目前抓到的 encoding 會讓某個函式庫無法完成編譯,所以我修改了 Lib/io.py 這個檔案,然後把
encoding = locale.getpreferredencoding()

換成
encoding = "utf-8"

這樣就可以順利完成編譯了!

2008年1月24日 星期四

哪裡會用到 Python ?

如我們所知,Python 是一個 scripting language,只要有 Python 直譯器 (interpreter) 就可以執行 Python 程式。Python 在目前主流的作業系統如:Windows, Linux/Unix, Mac 等上都有相同版本的直譯器可以下載,你當然就可以在這些平台上撰寫 Python 程式。

從桌面系統的程式來說,Windows 上的 Python 可以透過 ctypes 使用 Windows API,也可以使用 IronPython 來結合 .Net framework 的程式庫;wxPython, PyGTK, PyQt, Jython 都是可以跨平台寫出 GUI 程式的函式庫,一些 GNOME 或 KDE 的 widget 就是用 PyGTK 或 PyQt 所寫出來的呢!而 Mac OS X 上當然也有 Python-Cocoa binding -- PyObjc 囉,這個只要灌好 Xcodes 就直接能用 Python 來寫 Mac OS X 應用程式。

除了桌面系統、個人電腦上執行的 Python 程式,在 Web 開發上也可以使用到 Python,除了直接使用 Python 的 CGI 函式庫或是直接處理 HTTP protocol,你也可以使用像是 Zope, Plone, TurboGears, django 等等 web 開發框架 (framework) 更直接地處理關於 web 的運算、顯示及資料儲存等。

另外,手持裝置當然也能執行 Python 程式,有人已經將 Python 直譯器放進破解的 iPhone/iPod touch, WinCE 系列的 smart phone 當然也能執行 Python,而 Symbian S60 也有弄出一套 PyS60,也就是讓你透過 Python 語言在 Symbian 系統上開發程式。

這樣乍看之下,Python 跟 Java 好像還有那麼一點點相像呢!不管是在 desktop, server, mobile device 都可以看到它們的影子,不過比起 Java, Python 的 code 可是輕巧得多,雖然 Python 有硬要縮排,以及稍稍殘廢的 OOP 架構等小缺點,但寫起 Python 程式,這些小缺點可說是瑕不掩瑜...

Python 已當選了 2007 年度程式語言,不如趁機來好好學學(寫寫)Python 吧!

喜歡 Python 的理由

第一次聽到 Python 的時候,只知道它是一個要認縮排的語言,對於這個限制雖然感到不解,卻也沒有仔細去思考它的設計哲學,直到過了很久以後,真的開始學了 Python,才開始愛上了這個大家都認為十分簡單的語言。
Python 有多簡單?大多數的人都可以在一個星期內快速上手。常見的資料結構也幾乎都可以用它內建的三種資料結構(tuple, list, dictionary)搭出來,資料結構中可以混合不同型別的資料,可以免除很多像 C++ 這類編譯語言的限制,使程式設計師能夠更關注在於該做的事,而不是該如何去做。而且絕大多數的系統都有提供 Python 的直譯器,所以它既可以跨平台,也不需要 compiler,很適合用在一些和效能較為無關的地方,像是 UI,因為修改非常方便!若是要計較效能的話,Python 要和 C/C++ 整合可是一點都不難,透過 swig/ctypes/sip 之類的工具,你可以很輕鬆地在 Python 裡呼叫以 C/C++ 所撰寫的函式。
其它的小地方,像是 Python 內建支援大數、複數、Unicode,甚至很特別地支援 if 1 < x < 2 這樣的寫法,都是很吸引我的特色。雖然我接觸 Python 的時間才短短兩、三個月,但是我實在太喜歡 Python 了,於是想要在這裡和大家分享我一些學習的心得筆記,希望可以幫助一些同樣想要入門的朋友們。希望大家多多指教。