Archive for the ‘Python’ category

化整為零的次世代網頁開發標準: WSGI

一月 27th, 2010

今天,我要介紹Python網頁開發的標準: WSGI,我個人在看見這類英文縮寫時,都一定會試著去記住它的全寫,因為縮寫本身一點意義都沒有,難以記憶,WSGI的全寫是』Web Server Gateway Interface『,它的發音有點像是whiskey,光知道這個名字還是很難理解這到底是用來做什麼用的,簡單的來說,它是Python定義網頁程式和伺服器溝通的介面,如果你有寫過CGI (Common Gateway Interface),它的作用基本上就是和CGI類似的功用,定義一個標準的溝通方式,讓你寫的程式可以和伺服器溝通,但是WSGI不是設計用來給任何語言使用的,它是設計給Python用的,而它其實是基於CGI的延伸,在Python的部份進一步做更多的定義,而因為他是基於CGI,所以它也可以和CGI的介面相容,只要透過一個轉接器,就能把WSGI的程式接到CGI,說了這麼多,相信大部份人對於WSGI是什麼還是一頭霧水,會有一堆疑問,為什麼有了CGI還要有WSGI? Middleware又是什麼? 這很正常,我一開始也對WSGI一點概念都沒有,接下來我們就來介紹WSGI的特色。

» Read more: 化整為零的次世代網頁開發標準: WSGI

如何評估比較程式語言

一月 8th, 2010

有人提到以過去的觀點來看現在的PHP是不公平的,確實我有好一陣子沒有碰PHP,對於新版的PHP並不瞭解,因此我花了一些時間檢視新的PHP規格,的確新版的PHP遠比我預料的進步許多,很多之前提到的問題有所改善,我承認上一篇文章說PHP很爛是在發洩過去對於PHP的種種不滿,有人認為程式語言沒有好壞,全部都事在人為,而我認為程式語言的好壞有主觀也有客觀的部份,當你討厭或喜歡一個程式語言一定有某些原因,但就客觀的來看語言的設計來講,PHP在早期真的是爛得一榻糊塗,是公認的爛,但是在當時少有選擇,能選的工具不多,就只有PHP,在累積夠久的不滿後就會一次暴發開來,對於現在的PHP5.3還有未來的PHP6而言,他已經跳離了以前的單純語言設計上的爛,往更好的方向前進,我能說PHP的壞話少了很多,因為當語言層面的問題大部份都解決了,接著就是哲學和個人喜好的問題了,對與目前和新版的PHP的誤解在這邊說聲抱歉

所以這篇我想說的,怎樣看客觀地評估一款語言的好壞,還有主觀地評估好與壞,很多人說程式語言沒有好與壞,只有適合和不適合,基本上我不認同這樣的說法,如果說兩種差別很大用途不同的語言拿來一起比較就很奇怪,但是如果是性質接近的語言都符合你需求,就可以做好壞的比較,不然你要怎麼做選擇? 就如同我們買車子好了,你的目的是載貨,買的自然是卡車、貨車,但是如果是轎車呢? 就算是卡車也有選擇的,程式語言也一樣,目前大部份人所見到的程式語言,都是所謂的』通用目的』語言,也就是說這樣的語言沒有預設任何用途,基本上他可以拿來做任何用途,很多人因為不知道要從何比較起,所以都說程式語言沒有好壞之分,只有適合和不適合,如果有一堆工具都適合,既然沒有好壞之分,那你又該如何做出進一步的評估與選擇? 適不適合不就是透過比較而來的嗎? 不比較怎麼知道適不適合? 這不是自相矛盾嗎? 只靠喜好嗎? 閉著眼睛亂選? 大家都知道車子我們可以比較它的馬力、耗油、安全評等,但是大多數人不知道程式語言該比較些什麼,而我今天所要說的,就是程式語言該拿什麼來比較

» Read more: 如何評估比較程式語言

The best choice to grab data from websites: Python + Twisted + lxml

九月 26th, 2009

This is a translation of my article 抓取網頁的最佳語言 : Python written in chinese

At first

At first, I used C/C++ to write programs for grabbing data from websites. I tried to write a library for these tasks, but I realized that it’s not easy to implement a HTTP client library. Then, I used cUrl library for downloading pages, but even with cUrl, it’s not productive. I had to to modify program frequently, the compiling time is costly. There was also no regular expression for C/C++. I also had to deal with many annoying details like memory management, string handling.

Then

After that, I was wondering, C/C++ is not a nice choice to grab data from websites. Why do I have to handle so many details? Why don’t I just use script language or other language? At first I was worrying about the performance, and then I realized that the performance of language is not the bottleneck. What’s more? I can get much more benefits if I use script language, it is easier to develop and debug. So I decided to find another solution for grabbing data from websites.

How about Perl?

Long time ago, I used Perl to write CGI programs, like guest-book, website managing system and so on. That said, Perl is a 『write-once』  language. Lots of Perl programs are full filled with short syntax and symbols. It is really difficult to read. And it is not easy to modularize Perl programs. It doesn’t support OO well. And there is no more new version of Perl. Even the new Perl is under construction, but it takes too long time, I still think it is almost dead. For these reasons and personal feeling, I don’t like Perl.

PHP

As a popular programming language designed for websites, I don’t think it is suitable to use in other situations. And although it is popular, it is really a bad designed language. It is also not an easy job to modularize PHP programs, it doesn’t support OO well, too. The name-space is also a big problem, there are so many function looks like mysql_xxxx, mysql_oooo. But even such a bad language got its advantage. That is: popular, popular and popular. Some one said that:

PHP is the BASIC of the 21st century

Well, what ever, PHP is out.

Lua

Lua is a light weight script language, almost everything about design of Lua is for performance. I wanted to warp C/C++ library for Lua, but there is also lots of weakness of Lua. It is not easy to modularize, too. And almost everything in Lua is designed for performance, its syntax is not so friendly. What’s more, there are little resources for Lua, I might have to build everything I need. So Lua is not on the list.

Java

Java is a language grows with Internet, it is absolutely qualified. But, I don’t like it because it is too verbose. And what’s more, it is too fat! I want to throw my laptop that has only 256MB RAM out the window when I am running Eclipse on it. I’m sorry, I don’t like Java. The guy I mentioned in PHP, also said that:

Java is the COBOL of the 21st century

Python

Finally, I postdd questions on PTT, then one recommend Python. Well, Python? WTF? I have never heard that before. And I searched it and ask some questions. Then I found that it is exactly what I want! It can be extended easily. If I need performance, I can write module in C for Python. And there are so many resources to use. You can find almost any Python libraries that you can imagine. Also, those libraries are easy to install, you can type 『easy_install』 to install almost everything you want. Most of script languages are not suitable for big program, but Python is not the one among them, it is easy to modularize, and it supports OO well. What else, it is really easy to read and write. There are also lots of big guy use Python, like Google, YouTube and so on. When I decide to learn Python, I buy a Learning Python and start my journey with Python.

Fall in love with Python

It did’t let me feel disappointed. It is very productive to develop with Python. I wrote almost everything that I did in C/C++ before. But for grabbing data from websites, there is still lots of work to do.

Twisted

It is really a piece of cake for Python to get a web page. There are standard modules, urllib and urllib2. But they are not good enough. Then, I find Twisted.

Twisted is an event-driven networking engine written in Python and licensed under the MIT license.

It is very  powerful. It has beautiful callback design for handling async operations named deferred. You can write one line to grab a page:

getPage("http://www.google.com").addCallback(printPage)

You can also use its deferred to handle data

d = getPage("http://www.google.com")
d.addCallback(parseHtml)
d.addCallback(extractData)
d.addCallback(saveResult)

What’s more, I wrote an auto-retry function for twisted to retry any async function automatically, you can read An auto-retry recipe for Twisted.

Beautifulsoup

It is not a difficult job to get page from a website. Parsing html is a much more difficult job. There are standard modules of Python, but they are too simple. The biggest trouble of parsing html is: there are so many websites don’t follow the standard of html or xhtml. You can see lots of syntax error in those pages. It makes parsing become a difficult job. So I need an html parser that can deal wrong html syntax well. Then, here comes BeautifulSoup, it is an html parser written in Python, it can handle wrong html syntax well. But there is a problem, it is not efficient. For example, you want to find a specific tag, then you write:

soup.find('div', dict(id='content'))

It is okay when you do this in a small page. But it is a big problem if you do that in a big page, its tag finding method is very very slow. At first, I expect the bottleneck will be on network, but with beautifulsoup, the bottleneck is on parsing and finding tags. You can notice that when you run your spider, the CPU usage rate is 100% all the time. I run profile for my program, most of the time of running are in soup.find. For performance reason, I have to find another solution.

lxml

Then, I find a nice article: Python HTML Parser Performance, it shows comparison of performance of different Python html parsers. The most impressive one is lxml. At first, I am worrying about that is it difficult to find target tags with lxml. And I notice that it provides xpath! It is much easier to write xpath then find methods of beautifulsoup. And it is also much more efficient to use lxml to parse and find target tags. Here are some real life example I wrote:

def getNextPageLink(self, tree):
    """Get next page link
 
    @param tree: tree to get link
    @return: Return url of next page, if there is no next page, return None
    """
    paging = tree.xpath("//span[@class='paging']")
    if paging:
        links = paging[0].xpath("./a[(text(), '%s')]" % self.localText['next'])
        if links:
            return str(links[0].get('href'))
    return None
listPrice = tree.xpath("//*[@class='priceBlockLabel']/following-sibling::*")
if listPrice:
    detail['listPrice'] = self.stripMoney(listPrice[0].text)

With beautifulsoup, I have to write logic in Python to find target tags. With lxml, I write almost all logic in xpath, it is much easier to write.

Useful FireFox tool

With xpath, it is not a difficult job to find target tags. But it would be wonderful if you can try xpath on websites, right? I find there are some plugins of FireFox are very useful for writing spiders. Here are some useful tools for analysis:

FireFox插件XPath checker畫面

FireFox XPath checker

使用FireBug檢視網頁元素

FireBug

Example

I wrote an example to show how it looks like.

# -*- coding: utf8 -*-
import cStringIO as StringIO
 
from twisted.internet import reactor
from twisted.web.client import getPage
from twisted.python.util import println
from lxml import etree
 
def parseHtml(html):
    parser = etree.HTMLParser(encoding='utf8')
    tree = etree.parse(StringIO.StringIO(html), parser)
    return tree
 
def extractTitle(tree):
    titleText = unicode(tree.xpath("//title/text()")[0])
    return titleText
 
d = getPage('http://www.google.com')
d.addCallback(parseHtml)
d.addCallback(extraTitle)
d.addBoth(println)
 
reactor.run()

This is a very simple program, it grabs title of google.com and prints it out. Very elegance, isn’t it? :D

Conclusion

One year has been passed since I wrote this article in Chinese. Today, I still use Python + Twited  + lxml for grabbing  data from websites. You might not agree what I said, but they are best tool to write spider (crawler or whatever) for me.

An auto-retry recipe for Twisted.

九月 26th, 2009

You can find chinese version of this article here : Deferred應用的實例 : retry

For grabbing pages from websites with twisted, you can write this:

getPage("http://www.google.com").addCallback(printPage)

But what about the HTTP server is too busy to response? Your getPage fails. For reasons, you have to modify your program to retry once the getPage failed. So you might write a method like this:

getPageRetry(5, "http://www.google.com")

Well, it seems works fine, but how about you got some other operations to retry? connectToClient, getTime and so on. You have to write

connectToClientRetry(5, "example.com")
getTimeRetry(5, "timeserver.com")

You have to write retry-version version of every function that may fail. That’s not a good idea. Twisted provides a very beautiful ansyc callback object named Deferred. It looks like Chain-of-responsibility, but it can also handle errors well. With its beautiful design, I wrote a retry function that can warp all function return Deferred that might fail. That’s no need to modify any exists code of getPage to make it to retry automatically. Here is the recipe:

import logging  
 
from twisted.internet import defer  
 
log = logging.getLogger('retry')  
 
def retry(times, func, *args, **kwargs):
    """retry a defer function 
 
    @param times: how many times to retry
    @param func: defer function
    """
    errorList = []
    deferred = defer.Deferred()
    def run():
        log.info('Try %s(*%s, **%s)', func.__name__, args, kwargs)
        d = func(*args, **kwargs)
        d.addCallbacks(deferred.callback, error)
    def error(error):
        errorList.append(error)
        # Retry
        if len(errorList) < times:
            log.warn('Failed to try %s(*%s, **%s) %d times, retry...', func.__name__, args, kwargs, len(errorList))
            run()
        # Fail
        else:
            log.error('Failed to try %s(*%s, **%s) over %d times, stop', func.__name__, args, kwargs, len(errorList))
            deferred.errback(errorList)
    run()
    return deferred

Here you are! Now you can use it to make your operation to retry automatically!

from twisted.internet import reactor
from twisted.web.client import getPage  
 
def output(data):
    print 'output', data  
 
def error(error):
    print 'finall error', error  
 
d = retry(3, getPage, 'http://www.google2.com')
d.addCallbacks(output, error)  
 
d = retry(3, getPage, 'http://www.google.com')
d.addCallbacks(output, error)  
 
reactor.run()

Autostart script for TurboGears2

九月 20th, 2009

When I complete a TurboGears2 application, I got a problem, how to keep my tg2 application always running on Webfaction? You know, there is scheduled downtime of virtul host. Therefore, if you just run 『paster serve –daemon production.ini』, once the machine down, your application is down, too. So you have to find a way to keep your tg2 application up. I can use crontab to check tg2 application every 5 minutes, but during the just-start-up 5 minutes, your application is not working, so it is not a good idea. I notice Webfaction use a autostart CGI script for TurboGears1 application. So I decide to use that autostart CGI script to run my tg2 application. You might ask, what is autostart and how it works? Autostart script is a simple script to keep your web application up. It is executed when mod_rewrite of apache can’t connect to your server. By using autostart script, the application runs on-demand! If there are no users browse your application, it’s no need to run your application, that saves your memory usage.

However, the autostart Webfaction provided is for tg1, so I modify it for tg2, here is the modified version of autostart:

<![CDATA[
#!/bin/env python2.4
import os
 
# Test if the process is already running
running = False
# read status of tg2 application
lines = os.popen(
    'source /home/victorlin/webapps/tiange/tg2env/bin/activate;'
    'cd /home/victorlin/webapps/tiange/tiange/tiange;'
    'paster serve  status production.ini').readlines()
line = lines[0]
if line.startswith('Server running in PID'):
    running = True
 
print "Content-type: text/html\r\n"
if running:
    print """<head><META HTTP-EQUIV="Refresh" CONTENT="2; URL=."></head><body>
    Site is starting ...<a href="." mce_href=".">click here<a></body>"""
else:
    print """<head><META HTTP-EQUIV="Refresh" CONTENT="2; URL=."></head><body>
    Restarting site ...<a href="." mce_href=".">click here<a></body>"""
    os.system(
        'source /home/victorlin/webapps/tiange/tg2env/bin/activate;'
        'cd /home/victorlin/webapps/tiange/tiange/tiange;'
        'paster serve  daemon production.ini')
]]>


By the way, you can also use this script for Pylons applications. I hope this simple autostart script would be helpful :D

作品集更新 : 幾何圖形繪圖以及手繪辨

八月 26th, 2009

最近的一個案子終於算是結束了,簡單地介紹一下這個軟體,跨平臺的幾何圖形繪圖和手繪辨識的功能

pys_fill

可以用各種方式填色

pys_frame

不同的框線

pys_rotate

每個物件都可以自由旋轉和變形以及位移

pys_alpha

物件可以設定透明度

pys_linux

當然,這軟體是跨平臺的,這是在ubuntu下執行的畫面,原本當我在windows下寫完丟到ubuntu下執行,我猜想可能會遇到一些煩人的跨平台問題要解決,不過很順利地,一切就像在windows下一樣,wxPython看來真的是跨平臺的好選擇

接著是抓圖沒辦法展示的功能,手繪辨識和無限次數復原和重做,請看影片

手繪辨識是裡面最難寫的功能,讓我把我學過的數學都搬了出來,象皮擦的部份也是很複雜的運算,這整個軟體裡用到的幾乎都是線性代數的知識,我很自豪的一點就在於大部份我學過的東西都在實際應用上用得上

用Python幫你進行代數運算 : Sympy

八月 25th, 2009

最近因為接到的Case,滿腦子中都是線性代數的東西,程式中有太多東西需要計算,以前學過的東西全都從腦子裡挖了出來,不過我通常都不背公式的,我所做的都是將當時走過的思路再走過一次,把公式重新導出來,因為公式是一個點,忘記就沒了,而思路是一條線,只要抓到了就可以得到同樣的結果

我還記得有一次,在PTT站上問一個微積分的式子是怎麼來的,因為我在書上看到他經過一個很奇怪的上下乘某個三角函數,式子就莫名奇妙的跑出來了,有個台大的學生很不以為然的回答,就是上下相乘那三角函數阿,當時讓我覺得挺無言的,這我當然也知道,看書也知道,問題是在於,如果沒有書跟你講,你是怎樣能想到這神來一筆,知道要上下乘這個函數? 所以公式的結果從來都不是重點,重點在於思路,只死記公式最後都會忘光光,但是能夠思考而走到公式這一步的話,就好像走過一條路,找到片段,又能找到終點,死記公式,就好像把你丟到一個定點,要你記住那裡長什麼樣子,一個是點,一個是一條路,當然是思路記得比較好

這種想法讓我到了應用時通常都能用上我所學到的,因為我知道那些東西從哪裡來的,即使忘記了也可以再導出來,但同時有些時候也讓我吃足了苦頭,還記得有一次考物理時,前面半節課我在導公式,後面半節用導出來的公式算,下場當然很慘,其實很多時候公式寫到一個地方,剩的就只剩整理,但是這過程卻很煩人、機械化,很容易一個正負號,一個看走眼就會讓後面的過程全部跟著錯掉,所以不得不在過程中每個符號小心的重寫一次,長久以來我一直在想,即使是整理也是有規則的,為什麼不能用電腦來算呢? 雖然我知道有matlab這類的東西,畢竟沒時間學,領域也不太一樣,不合胃口,直到前陣子在PTT的Python版上看見有人推薦一款Python的library : Sympy,他是一款Python寫的代數運算函式庫,舉個例子你寫出了一個式子,想知道它的導函數是什麼,你只要先將式子列出來,再用一個函數呼叫,他就可以把導函數算出來,這非常地合我喜好,我們現在就來介紹如何使用Sympy來幫你計算兩線在平面交一點的公式

兩線交一點

首先我們在平面上有P1和P2兩點,而從P1出發的是u向量,從P2出發的是v向量,我們想得知這兩條線在哪裡會交一點,就必須這麼算,我們設t和s為實數,我們可以找到一個等式P1 + su = P2 + tv,也就是P1以u的速度走s秒(秒只是幫助想像的假設),P2以v的速度走t秒,兩人會撞在一起,要導公式就要先找等式,這就是我們公式的等式,一開始我不知道是程式寫太多還怎樣,突然有點腦殘的想說,奇怪,這式子有兩個未知數s和t,一條式子算不出兩個未知數阿? 後來才突然想到,我忘了這是平面,所以在x分量和y分量上面我們各有一條這樣的等式,有了兩條等式,兩個未知數才可能有解

f1

f2

有了等式之後,嘿嘿,就是該交給電腦的時候了

from sympy import *
 
p1x = Symbol('p1x')
p1y = Symbol('p1y')
 
p2x = Symbol('p2x')
p2y = Symbol('p2y')
 
ux = Symbol('ux')
uy = Symbol('uy')
 
vx = Symbol('vx')
vy = Symbol('vy')
 
s = Symbol('s')
t = Symbol('t')
 
fx = p1x - p2x + s*ux - t*vx
fy = p1y - p2y + s*uy - t*vy
 
sol = solve((fx, fy), s, t)
 
print 's:'
pprint(sol[s])
 
print 't:'
pprint(sol[t])

就是這樣簡單直覺,你可以先去吃個飯等他算完嗎? 不,連屁股都還沒挪開椅子就算完了

formula

最後

附上一張用小畫家手導公式的惡心算式圖,高下立判,我當時算出了t,正想說要把t代回公式裡算出s時就頓時覺得頭皮發麻,好煩喔,於是就找了sympy來試用,果然一眨眼的功夫,我式子列完了,公式也算完了,就是這樣!

scribble_formula

Python使用HGE引擎

八月 25th, 2009

大家肯定都知道在Python下面寫2D遊戲有個眾所階知的選擇就是pygame,雖然它簡單好寫,對於簡單的遊戲來說已經足夠,但是他有一個致命的缺點,就是速度太慢了,在pygame的背後是SDL,用純軟體畫圖的函式庫,既然為純軟體繪圖,遇上旋轉、半透明等等需求,更顯得吃力和不切實際,所以該怎麼辦才好呢?

答案是用Haaf’s Game Engine,它是一款用DirectX做為backend的Open source遊戲函式庫,我在先前的文章裡已經有做簡單的介紹,就不再重覆,那這函式庫和Python又有什麼關聯呢? 他是用C++寫的,Python沒辦法用,正因為這樣,我一直一來想幫他寫一個python的binding,我一直想如果Python也能用HGE寫起來一定很開心,我試著找了一下有沒有已經存在這樣的專案,有找到一個,但是居然是在萬惡的GNU授權下的,讓我百思不得其解,那專案的作者到底在想什麼? 想讓大家寫Open source的Game嗎? 我們都知道GNU是大名頂頂的病毒授權,任何程式使用了用GNU的函式庫都會被感染,代表你的主程式一樣得變成GNU的開源授權,我個人非常討厭打著自由名義但是卻有強烈的強迫性質的GNU授權,況且HGE的授權是非常寬鬆的 zlib/libpng License,實在想不透為什麼一個binding可以用超嚴格的GNU,不過那是那作者的自由,我也管不著,在不能接受那惡心的授權,加上我看了一下他的專案似乎好像也沒有很完整的進度,於是我還是決定自己開了一個新的專案

Python HGE

在這樣的情況下,我前些天抽空開了一個新的Open source專案: Python-HGE,把一些最核心的程式碼都用boost.python包裝給Python使用,最核心的部份完成度很高,剩下的需要我在未來有空慢慢補上,License是MIT,如果你問我為什麼選MIT,我想答案應該是商業用途一樣也可以,不像GNU那種假腥腥的自由,還有一個重點就是,我覺得麻省理工這名字聽起來很酷,讓我想起每次在Discovery看到的東西

效能問題

我照著原本HGE的Tutorial7的程式寫了一個Python的版本,這個範例的目的就是在展示HGE的效能,純C++的版本速度當然是很快,而Python的版本FPS掉了不少,一開始讓我覺得有點失望,讓我開始懷疑如果效能掉很多的話,那用Python寫HGE還有價值嗎? 後來仔細思考了一下,對於一般的2D遊戲來說,要像這demo整畫面跑來跑去的圖片加透明效果的情況實在不多,就算有也很難到這樣上千張的圖片,再者我都還沒進行最佳化、跑profile等等,而且雖說FPS掉不少,但是那是和C++數百的FPS比起來,在60以上其實都是可以接受的,加上我測試的這台電腦已經有點年代,對現代的電腦和GUP來說情況只會更好,在如此的考量之下,Python HGE還是有搞頭的

python版的tutorial 7截圖

t7

這個demo可以在這裡下載

目前狀況

目前雖然核心部份已經高度完成,不過我還沒有把編出來的pyd釋放的打算,如果想嘗鮮的話可以直接從那個demo裡面找pyd出來用,又或著自己check out原始碼進行編譯

參與開發

如果有興趣的話,歡迎參與專案的開發,如同我上面所提到的,我用的是boost.python,一款基於C++的python binding函式庫,如果你熟悉boost.python的話當然是最好,就算沒有也沒關系,因為其實大部份工作都是剪下貼上之類的,可以參考我已經寫好的部份,有些函數回傳例如指標之類的東西需要特別處理,除此之外都只是很簡單無腦工作

wxPython自製Control : 用Matplotlib畫圖表的FigurePanel

七月 22nd, 2009

最近可能會接到一個需要GUI上畫不少圖表的案子,於是就來研究了一下wxPython + matplotlib,前陣子買了wxPython in action,雖然一本1500元大洋讓我心有點淌血,不過這本書真的寫得很棒,讓我對wxPython有更深入的瞭解,如果案子接下來買n本都可以,我個人認為買書來讀是一種投資,所以基本上看上眼的書買起來也不會手軟,接著因為除了畫圖形,也需要用到不少GUI,我把wxPython官方的demo抓下來,裡面每個範例都跑了一次,對於wxPython能做到什麼地步有了更深入的瞭解,越來越覺得wxPython真是酷斃了,很好玩的GUI framework

在這之後,雖然案子還在歸劃的初期,不過我不是很喜歡空等而沒有程式可以寫的感覺,其實在接洽的這段期間就能先完成一些將會用到的東西,像是widget之類的,或寫寫原形來驗證確實可行之類的都很好,所以我就寫了一個用Matplotlib畫圖表的Control : FigurePanel,因為往後在寫GUI都會用到,如果每次都要特地寫來處理這些我會發瘋,當然最好的方法就是包成Control,如此一來所有圖表都可以直接使用,加上可以有統一的行為,例如另存新檔、列印等等,相當方便

什麼是Matplotlib? Matplotlib是一套強大的Python畫圖表用的函式庫,如果不知道他到底可以畫到什麼地步,就可以看他們官網的畫廊,相信看完後就知道它有多強大,幾乎你想得到的圖、想不到的圖,沒看過的圖,他都可以畫,當然,如果裡面沒有你要的圖,或著你要自創圖,當然也可以自己擴增,有了這套函式庫,原本我可能得先花個一個星期還多少時間來建構一套畫圖表的基礎,如今這些時間完全省了下來,這就是使用Open source的好處,沒有這些東西真的不知道要寫到民國幾年

切入正題,我們來看一下FigurePanel的原始碼

» Read more: wxPython自製Control : 用Matplotlib畫圖表的FigurePanel

開發wxPython的利器 : PyCrust

六月 17th, 2009

一直想做的事

最近我在用wxPython開發某些程式,隨著開發的過程中,難免需要一些直接的測試,改動程式碼來進行測式似乎不是很明智的選擇,即使Python是直譯式的語言,每改一次重新啟動整個程式也是一種浪費,而且狀態每次也會重置,於是我開始想,我是否可以寫一個像Half-Life那樣的一個console整合到我的GUI中,如此一來我就可以在開發時直接進行某些測試,對某些特定的模組操作,如此一來開發的效率可以提升,對於程式而言也會更好除錯,但是雖然寫一個console不是什麼太難的事,但也不是什麼太輕鬆的事,為了早點完成程式,於是我就沒有真的去做

直到某本書的出現 : wxPython in action

當有一天我訂的書: wxPython in action終於來了,這本書要1500元,實在是不便宜,但是我認為卻很值得,我在書中發現我以前一直都沒仔細去注意到的東西,PyCrust,在翻過這章節時我驚訝地發現,這不就是我想做的嗎? 一個控制臺,可以讓我操作、觀察、測試我的GUI,而且整合的方法超簡單,只要一行指令

python pywrap.py main.py

在wx.py的package下的pywarp.py會自動找到app並且將PyCrust整合進去,在我程式中執行的畫面就像這樣

pycrust

在截圖中我利用pycrust將gui的背景換成了紅色,它不止是一款簡單的GUI,因為他是動態載入模組的name space,和一般IDE不同的是,他的自動完成是動態的,一般的IDE只抓得到靜態的成員,但是即然是動態載入又是在執行中,有什麼成員一清二楚,所以基本上自動完成功能感覺非常地強大,但相對的弱點是對於靜態的部份比較麻煩

它除了可以自動整合到現有的wxPython gui程式中,更可以把裡面各個元件分開來獨立使用

所以它可以幹麻?

對我來說,PyCrust將會是像神兵利器般好用的工具,像是開發遊戲之類需要大量的調校,一個console或是動態的機制是免不了的,而console提供了立即且互動式的環境,有了PyCrust,就等於有了現成的console可以使用,在遊戲的開發過程中,開發者可以利用這個console動態地改變各種參數來觀察反應等等,當然開發遊戲只是其中一個應用的例子,即使在一般的GUI中也會是很好用的工具

順帶一提

wxPython in action真的是難得一見的好書,有別於一般的書,它使用問句來當做標題,但是不會因為這樣而零散雜亂,相反的,你可以很正式地看完一次,也可以很快速地掃過一次,當你需要什麼東西時,那些問句可以幫助你很快地找到你需要的東西,豐富的截圖和圖解更讓人不用費心去猜想到底做出來會是什麼樣子,或是想像到底是如何運作,如果要學wxPython,我覺得這本書真的是非常值得推薦,做為工具書,這本也是必備的一本