顯示具有 Python 標籤的文章。 顯示所有文章
顯示具有 Python 標籤的文章。 顯示所有文章

2009年1月4日 星期日

windows 上讀寫檔案會遇到的問題

這是我在一個論壇裡面 post 的文章,其實我也常常忘記為什麼會被置換,每次都要重想一遍 =P ,所以貼來這邊作紀錄。




若不使用 binary mode 讀取寫入檔案,在 windows 上讀取與寫入分別會遇到的問題有:

讀取:
對 windows 來說,Ctrl-Z(1A) 也算是檔案結尾,因此只要遇到 hex 1A ,就會看到它停止讀取。

所以可以看到本來陋陋長的檔案變成只有一點點大

寫入:
我們一般在撰寫 python 程式的時候,標準的換行字元都是 \n(0A),所以如果我們要排版一個 string,我們都會做這樣的動作


>>> str = '老師您好:\n我是bmcool'
>>> print str
老師您好:
我是bmcool
>>>


但我們都知道 windows 的標準換行字元為 \r\n(0D0A) ,跨平台的腳本語言都會有這種自動偵測與轉換的能力,因此當你沒有交代你即將寫入的資料為 binary 時,python 為了讓你排版美美的字串在 windows 上有一樣的排版效果,就會很雞婆的幫你把 \n 轉換成 \r\n ...

也就是圖片中只要含有 hex 0A,全部都會變置換成 hex 0D0A ... 可以把上述範例的 str 寫入檔案,並用 16 進制編輯器打開來看看,就會發現是怎麼回事了。



Mac 的標準換行字元為 \r,對 python 來說也會有一樣的影響,它會把所有的 \n 都換成 \r ...

Linux 的標準換行字元與 python 相同,都為 \n,因此不會有任何轉換。

2008年11月20日 星期四

Glade 的第一個 hello world

還真是辛苦 ...

網路上充斥著不能用的範例,大概是版本不同的關係 ... 搞了好久才弄出第一個 hello world ...

hello.py
# coding=utf-8

import gtk
import gtk.glade

class HellowWorld:
    
def __init__(self):
        
self.wTree = gtk.glade.XML('hello.glade') 
        
        
# 抓 glade 檔案裡面的 id="hello"
        
self.window = self.wTree.get_widget("hello")
        
# 如果有抓到這個物件
        
if (self.window):
            
# 關閉視窗時,執行 gtk.main_quit (其實就是把 GUI 關掉)
            
self.window.connect("destroy", gtk.main_quit)
            
            
# 就是少了這個害我畫面都出不來!
            
self.window.show()

if __name__ == "__main__":
    
hwg = HellowWorld()
    
gtk.main()



這是hello.glade,可以自己用glade3拉拉看
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
<!--Generated with glade3 3.4.3 on Thu Nov 20 00:42:25 2008 -->
<glade-interface>
  
<widget class="GtkWindow" id="hello">
    
<child>
      
<widget class="GtkLabel" id="lab1">
        
<property name="visible">True</property>
        
<property name="label" translatable="yes">hello</property>
      
</widget>
    
</child>
  
</widget>
</glade-interface>

2008年11月18日 星期二

安裝 PyGtk 與其他相關套件

本來我是打算挑選 wxPython 做為 Python 語言的主力 GUI 工具,原因我已經忘了 ... 在沒有這個網誌之前就綜合網路上意見所決定的。

但還沒有開始研究 wxPython ,就突然因為工作關係必須開始學習 Gtk 了。雖然我已經忘記為什麼當初決定使用 wxPython ,但隱約記得 Gtk 給我的感覺並不好,但不是在開發階段,而是安裝階段 ...

不過不管怎樣,現在回頭來看 Gtk ,似乎感覺也是不賴的,當然我並沒有能力評斷兩種工具撰寫 code 的優劣,畢竟我只有用這兩種工具寫過小量的例子。





這邊做一些網上找回來的紀錄,都還只是網路上的片段句子,有空再回來証實並整理。


PyOpenGL 的安裝必須依靠 setuptools ,可以參考這個網站。
http://www.ibm.com/developerworks/cn/linux/l-cppeak3.html


PyOpenGL 的官方網站就在這囉 ...
http://pyopengl.sourceforge.net/


要讓 pyGtk 可以使用 OpenGL 的一些函式,就必須安裝 PyGtkGlExt (Python Gtk GL Extension?)才可以。底下這個官網也有 all-in-one ,可以一口氣安裝 PyGtk 、 PyOpenGL ... etc
http://www.k-3d.org/gtkglext/Main_Page


主角之一的 Gtk 官方網站
http://www.gtk.org/


其實真正要動只要安裝這個應該就可以動了 ... (可以在 Python 中 import gtk)
Gtk runtime++


glade 是可以為 Gtk 產生拖拉點放碼的工具,已經附在gtk-dev-2.12.9-win32-2.exe,但要更改一下它的捷徑 ... 要指向 C:\GTK\bin\glade-3.exe (不知道為什麼他原本是C:\GTK\bin\glade-2.exe)



這是可以參考的網站之一
http://vpoohtw.blogspot.com/2008/05/pygtk.html


至於 pyWin32 是可以利用 python 與 windows 的一些應用程式(如 outlook)溝通的套件。


pyCairo 是可以讓 Gtk 擁有比較炫的圖案


ATK(Accessibility Tool Kit) 讓程式能提供更友善、更易於操作的介面。


Pango 則是處理多國語言的好幫手 ...


這是一個 C 的 Gtk 的教學網站,有踩地雷的實例
http://debian.linux.org.tw/~kevpeng/




先這樣,有空再來整理 ...

2008年11月6日 星期四

object & return

Python 的 class 功能真的比我想像中的強大多了 ...

這是一個範例,它定義了 object 各種需求的 return function
class a:
    
def __int__(self):
        
return 123456789
    
    
def __str__(self):
        
return 'this is a string'
    
    
def __unicode__(self):
        
return 'unicode here'



使用起來會像這樣
>>> s = a()
>>> int(s)
123456789
>>> str(s)
'this is a string'
>>> unicode(s)
u'unicode here'



可以應用在蠻多場合的!

2008年11月5日 星期三

class處理未宣告的method

class 有一個很神奇的 method,只要你在 class 中有宣告 def __getattr__(self, name),它便會把所有無法處理的優先丟給它處理。


這是一個範例
class controlMethod:
    
def otherMethod(self, name):
        
def method(*args, **kwargs):
            
print name, args, kwargs
        
return method
    
    
def __getattr__(self, name):
        
return self.otherMethod(name)
    
    
def hello(self):
        
print 'hello world'




使用起來會像這樣...
>>> c = controlMethod()
>>> c.hello()
hello world
>>> c.nono(1,2,a='die')
nono (1,2) {'a': 'die'}




在不同的應用上,也可以這樣設計
def method(*args, **kwargs):
    
print args, kwargs

class controlMethod:
    
def __getattr__(self, name):
        
return method
    
    
def hello(self):
        
print 'hello world'

2008年10月23日 星期四

Python的doctest

我想了想,還是要來一個最簡單的doctest。每次我去看一些高手的網站,他們介紹模組都是用一個不算小的範例(果然是高手),但可能我要的只是一個最最簡單的範例。畢竟身為Python初學者的我,還不知道什麼是內建變數或是函式,也不知道是否要固定格式,我知道的只有最最基本的語法而已,所以每次看到一大串,我都還得分析過濾哪些才是真正的「模組範例」...

這是範例
mul.py
# coding=utf-8

'''
寫一個簡單的乘法功能
'''


import doctest

def mul(x, y):
    
'''
    >>> mul(100, 200)
    20000
    
    如果不小心範例寫錯了...就會回傳錯誤
    >>> mul(1, 2)
    1
    '''

    
    
# 這裡才是真正mul的內容
    
return x * y

# 這行的意思是指當此檔案為主程序時,才執行doctest.testmod()
if __name__ == '__main__':
    
doctest.testmod()


這是執行結果

發牌程式、doctest、unittest

記得之前曾經用Tcl寫過發牌程式,那時候大概的邏輯是
1. 產生52張牌,並依序放入一個list中
2. 產生0-51的亂數,當作index
3. 用index從list中取出牌
4. 從list中移除這張牌

其實也是沒寫幾行就搞定了。

但後來看到python的random模組提供了一個函式shuffle,這個函式的作用就是將list內的東西打亂,於是我又想到了發牌程式,其實這樣比較符合現實生活的「洗牌」與「發牌」行為。

邏輯是這樣的
1. 產生52張牌,並依序放入一個list中
2. 打亂52張牌的順序
3. 從第一張開始pop(取出並移除)出來


是不是很像人類在發牌呢?


但會寫這個主要是想要玩玩看doctest與unittest。

這兩樣在測試上都有其好用的地方,doctest非常適合一些簡易的測試,它可以讓註解等於測試,這樣很多習慣不良的開發者半強迫式的有了兩種習慣
1. 每一個function都會寫註解及範例
2. 每一個function都會寫測試程式

但畢竟是註解型測試,要忠實執行TDD(Test-driven development),可能還是得依靠unittest。

底下是 發牌程式 + doctest 與 unittest 兩段code

這是發牌程式 + doctest
dealer.py
# coding=utf-8

'''
只是一個簡單的發牌程式
'''


import doctest
import random

class dealer():
    
def __init__(self):
        
'''
        產生一副撲克牌
        '''

        
self.reset()
    
    
def reset(self):
        
'''
        重新產生一副撲克牌
        >>> d = dealer()
        >>> nothing = d.deal(1)
        >>> d.show().__len__() == 51
        True
        >>> d.reset()
        >>> d.show().__len__() == 52
        True
        '''

        
self.pokers = []
        
        
for pattern in ['spade', 'hearts', 'diamond', 'club']:
            
for number in range(1, 14):
                
self.pokers.append(pattern + str(number))
        
self.pokers.sort()
    
    
def shuffle(self):
        
'''
        洗剩下的撲克牌
        >>> d = dealer()
        >>> d.shuffle()
        >>> first = d.show()
        >>> first.__len__() == 52
        True
        >>> d.reset()
        >>> second = d.show()
        >>> second.__len__() == 52
        True
        >>> first == second
        False
        '''

        
random.shuffle(self.pokers)
    
    
def deal(self, number=1):
        
'''
        指定數目從牌庫中發出剩下的撲克牌
        >>> d = dealer()
        >>> nothing = d.deal(1)
        >>> d.show().__len__() == 51
        True
        >>> nothing = d.deal(51)
        >>> d.deal(1)
        'None'
        '''

        
        
# 如果指定的數目大於剩下的牌數,就把所有剩下的牌發出去
        
if self.pokers.__len__() < number:
            
number = self.pokers.__len__()
        
        
result = []
        
for i in range(number):
            
poker = self.pokers.pop()
            
result.append(poker)
        
        
if result.__len__() != 0:
            
result.sort()
            
return result
        
else:
            
return 'None'
    
    
def show(self):
        
'''
        把牌庫中剩下的撲克牌印出來
        '''

        
return self.pokers

if __name__ == '__main__':
    
doctest.testmod()



這是unittest
test_dealer.py
# coding=utf-8

'''
test for dealer.py
'''


import unittest
import dealer

class DealerTestCase(unittest.TestCase):
    
def setUp(self):
        
self.d = dealer.dealer()
        
self.original = list(self.d.show())
    
    
def testshuffle(self):
        
self.d.shuffle()
        
        
pokers = self.d.show()
        
self.assertNotEqual(self.original, pokers)
        
        
pokers.sort()
        
self.assertEqual(self.original, pokers)
    
    
def testreset(self):
        
self.d.reset()
        
        
pokers = self.d.show()
        
self.assertEqual(self.original, pokers)
    
    
def testdeal(self):
        
for i in range(52):
            
poker = self.d.deal()
            
self.assert_(poker[0] in self.original)
            
self.assert_(poker[0] not in self.d.show())
        
poker = self.d.deal()
        
self.assertEqual(poker, 'None')
    
    
def tearDown(self):
        
pass

if __name__ == '__main__':
    
suite = unittest.makeSuite(DealerTestCase)
    
unittest.TextTestRunner(verbosity=2).run(suite)


檔名記得跟我取的一樣喔!

將這兩個檔案都放在同一個資料夾,便可執行test_dealer.py!

2008年10月22日 星期三

讓Python開發速度提升的IPython

IPython是為了Python所開發的的一種互動式介面(Interactive Shell)

大部分的直譯式語言都會有這樣的介面,但通常都只有簡易的命令式對答,其實在使用上並不是這麼方便,但Tcl就有一個非常成功的範例-「Tkcon」

可記錄歷史訊息,可利用tab自動完成字詞,可對GUI做一些簡單的調整與設計...等

而IPython就是一種功能強大的互動式介面,讓Python's Programmer可以更快速的開發,可以讓像我這樣的初學者更快的進入狀況

安裝方法如下:

照順序下載安裝以下兩樣套件

IPython的主程式
http://ipython.scipy.org/dist/ipython-0.9.1.win32-setup.exe
Ipython的相依套件 - pyreadline
http://ipython.scipy.org/dist/pyreadline-1.5-win32-setup.exe

安裝完成之後,便可以開始試試它的威力了!

2008年10月17日 星期五

Python與Debug

只要有IDE(Integrated Development Environment)的程式語言,通常都可以仰賴Debug Mode來完成Debug的大業,只是IDE往往都是架構在GUI上,因此沒有顯示器的系統可能就無法享受這樣的便利性了。

而且有些程式語言要安裝IDE,實在是非常非常的麻煩,還要準備足夠的硬體資源來應付這樣的怪物。

至於Python Debug Mode完全是用Python Code來撰寫,還真的完全發揮了跨平台的實力,可以輕鬆移植到任何可安裝Python Interpreter的作業系統,而且不需要GUI就可以使用。

底下是一個簡單的範例

# coding=utf-8
def add(x):
    
value = '1'
    
return x + value

add(1)


執行這個檔案會出現以下的訊息

可以發現其實還是不知道錯誤到底在哪。

這時候若是直接打開檔案,當程式不多的時候,可以輕鬆的用肉眼判斷加法運算是不可以把數字與字串加在一起的,但程式很大的時候呢?

這時候就需要用到Debug Mode了


進入到command line模式(Windows=cmd.exe)
用Debug Mode執行檔案
python -m pdb add.py





然後下達這些指令(圖片底下為逐行解釋)




在(Pdb)模式下

設置breakpoint 3,可以比照第一次執行檔案時,發生錯誤的行數
b 3



開始執行程式直到breakpoint
r



開始檢查此行究竟發生何事?
x + value



印出x
x



印出value
value

原來是value為字串


試著將value更改為int型態
value = int(value)



繼續執行程式
r

成功return 2!

2008年10月13日 星期一

利用python的http套件將網路上的圖片抓下來

一個簡單的範例
# coding=utf-8

# 載入urllib2模組,可以處理http
import urllib2

# urllib2.urlopen會回傳一個http object
token = urllib2.urlopen('http://l.yimg.com/tw.yimg.com/i/tw/hp/spirit/yahoo_logo.gif')

# 開啟一個二進制檔案
f = open('yahoo_logo.gif', 'wb')

# 把圖片的內容放進這個檔案中
f.write(token.read())

# 關閉檔案
f.close()



這樣就會產生一個叫yahoo_logo.gif的檔案在執行路徑下了