2012年5月17日 星期四

[Python]Python和C之間的差異 - Python的型別和物件

這篇文章主要是想幫助那些從C轉換跑道到Python來的程式設計師
首先先解釋一個差異很大的地方,Python的型別(types)和物件(objects)

在Python中所有的東西都是object

string是object,int是object,function是object,連code都是object
這點和C或是C++非常的不同
我們可以用一個內建的function type()來得知一個object的type
>>> s = "sway"           #"sway"是一個string的object
>>> type(s)        
<type 'str'>
>>> i = 2                #2是一個int的object
>>> type(i)
<type 'int'> 
>>> def hello(): pass    #hello()是一個function的object  
...
>>> type(hello)
<type 'function'>
>>> type(hello.__code__) #hello()的code是存在一個code的object 
<type 'code'>

Python是動態型別(Dynamic Typing)的程式語言,和C和C++這類的編譯語言不一樣
C和C++變數的型別都在編譯時候就決定好了
而Python則是在執行期(Run Time)才決定type
>>> s = "sway"    #這時候s的type是string
>>> type(s)

>>> s = 2         #這時候s的type變成int了
>>> type(s)








由上面範例可以帶出一個Python很重要的觀念
Python variable的type完全被它所對應到的object所決定的
這在Python中稱為reference
每一個variable其實就像是C裡頭的pointer
先建立object之後,才用variable指向新建立的object,相當於給object一個別名
因此Python的variable其實就是reference

當我們執行i = 2的時候,其實Python會先建立一個integer的object叫做2
之後再產生一個variable並且把它指向2這個integer的object
Python的variable其實就只是一個name而已,我們透過這個name去間接access到object
這點是Python和C、C++很不一樣的地方,這也是大多數C programmer剛轉過來不太適應的地方
由於Python的這種特性,很多神奇的事情就發生了
>>> a = [1, 2, 3]
>>> b = a
>>> b[0] = 4
>>> print a
[4, 2, 3]
很多人看到這邊可能會覺得很奇怪,明明是修改b的值怎麼連a的值也被改到了?













其實原因很簡單,因為b = a這行程式碼其實只是把b指到a所指向的object而已
因此當執行完這行程式碼後,a和b就都指向同一個object
不論是改a或是改b,最後都會對應到同一個object
這是Python初學者最容易詢問的問題之一,其實只要搞懂Python的object架構,一切就會變得很直覺

上面範例如果object是一個不可改變(immutable)的object,情況就有點不一樣了。不可改變(immutable)的object像是:string, integer......
因為object是不可改變的,當你嘗試去更改object的時候,會自動建立新的物件,而不會更動到所指向的object。
聽起來有點難懂,看以下範例就知道了
>>> a = 2
>>> b = a
>>> id(a)                #id(a)可以取得a指向物件的id
17500064
>>> id(b)
17500064                 #a 和 b指向同一個物件(integer 2)
>>> b = 4
>>> print a
2
>>> id(b)                #b指向一個新的物件(integer 4)
17500016
由以上範例可以知道,兩個reference指向同一個不可改變的object時。因為object不可改變的特性,透過其中一個reference試圖去修改object都會自動建立一個新的物件

相反地,兩個reference指向同一個可改變(mutable)的object時。因為我們可以直接修改object的關係,所以透過其中一個reference去修改object不會建立新的物件。會直接修改到指向的object,因此透過任何一個reference去取值看起來就好像兩邊都被改過一樣。

All "variables" are references. 這是Python和C很不一樣的地方。

2012年5月1日 星期二

大話處理器 : 了解DSP.CPU及MCU基礎架構


這本書是一本講解處理器內部運作原理的書,看得出來作者試圖用很多生活化的例子來解釋CPU內部運作的原理。大致上可以把這本書看成是一本簡單的計算機組織入門書,整本書的內容絕大多數都是從Computer Organization and Design以及Computer Architecture: A Quantitative Approach這兩本書而來。這本書的內容比較淺,作者跳過了很多細節。因此只適合完全不懂計算機組織的人來念,否則會覺得書中寫得內容太淺了。

書中前面幾章在講解電腦的歷史,以及介紹一些常見的CPU和DSP,這部份我覺得還蠻不錯的。這本書最大的缺點就在於翻譯品質,可能是因為兩岸用語不同的關係,許多地方寫得中文名詞都有點奇怪。這點在很多大陸翻譯書都會出現,國內出版社真的該好好改善這一部份。

總而言之,這本書可以帶你初淺的認識CPU的內部運作原理。不過詳細的細節還是建議去閱讀計算機組織的聖經 Computer Organization and Design以及Computer Architecture: A Quantitative Approach 這兩本書,這兩本書才能真正帶你瞭解CPU的世界是怎麼運作的。

2012年4月19日 星期四

[Python]自己定義例外處理

Python允許使用者自己定義一個新的例外處理
要建立一個新的例外處理很簡單:
class TestException(Exception): pass
上面程式碼定義一個新的例外處理叫TestException,並且繼承自一個Exception的Class
什麽時候要定義一個新的例外處理呢? 當要從好幾層迴圈離開的時候就很好用
以下是一個從許多表格中找出特定值的範例:
found = False
for record in table:
    for field in record:
        for item in field:
            if item == target:
                found = True
                break
        if found:
            break
    if found:
        break
if found:
    print "found"
else:
    print "not found"
傳統的寫法要從最內層迴圈一層一層break出來,程式碼變得很冗長
這時候可以定義一個新的例外處理,當找到target的時候就raise我們新定義的例外處理
如此一來程式碼可以變得比較簡潔
class FoundException(Exception): pass
try:
    for record in table:
        for field in record:
            for item in field:
                if item == target:
                    raise FoundException()
except FoundException:
    print "found"
else:
    print "not found"

2012年4月18日 星期三

[Python]目前執行的OS平台

在Python中要知道目前執行的OS平台很簡單
只需要去檢查sys.platform這個變數就可以了
sys.platform會保存目前執行OS平台的名字("win32" or "linux2")
因此我們可以用一行簡單的程式碼就知道目前執行的OS平台是什麽
isWindows = True if sys.platform.startswith("win") else False
這行程式碼在windows上執行時,osPlatform的值會被設成True
在其他OS執行的時候(ex: Linux, FreeBSD...),會被設定成False

2012年3月28日 星期三

嵌入式系統開機流程

1. CPU到指定的memory address抓取第一行instruction執行,有兩種常見的作法
    (1)CPU會把PC設定為一個特定的address,從這邊開始執行
    (2)CPU會把Interrupt Vector Table設定為特定的address,並且發出Reset interrupt
         在Reset的ISR中執行某個開機的function

2. 初始化CPU (IVT的addres, SP)

3. 把code和data從ROM或是 Flash搬到RAM上執行,通常使用DMA搬
    (有些code可直接在external flash上執行就不需要搬)

4. 初始化板子相關設定和參數

5. 初始化系統(ex 執行OS、GUI)

6. 執行主程式,很多嵌入式系統會執行一個無窮迴圈

2012年3月27日 星期二

在Windows底下dump DLL

問題:
今天碰到一個bug,有一個.net程式用到_controlfp_s這個function
在Win7底下是放在msvcrt.dll,但是在Win XP中的msvcrt.dll卻找不到這個function

找到此問題的方法: 
使用dumpbin把DLL的function name dump出來看
(有點像Linux底下的object dump)

步驟:
1.執行Visual Studio Command Prompt

2.C:\WINDOWS\system32>dumpbin /exports msvcrt.dll | more

解決方法:
更換XP和 Win7都有的function,或是在程式當中附上DLL檔

2012年3月14日 星期三

約耳續談軟體:探究軟體經營的根本實學

這本書是『約耳趣談軟體:來自專案管理的現場實錄』的續集,同樣是由充滿幽默感的約耳所撰寫。大部分文章其實之前在網路上都有人翻譯。約耳還是延續他一貫幽默的風格,很輕鬆就能讀完他。和前一本不同的地方在於,這本書主要的主題是在探討如何管理一間軟體公司,其實蠻適合主管和老闆來看看。這本書可以看到約耳對待員工以及如何管理他的公司,看了會很令人羨慕,面試時候不但有豪華轎車到機場接送,還免費住在高級的旅館並且在高級的旅館舉辦party。辦公室裡頭有私人的辦公室,坐得是一張900美金的椅子。就如同約耳文章所寫得,最好的管理就是找最優秀的人進來,讓他們認同你並放手讓這些專家自己去做。當然約耳的徵才標準也是非常高,他同時也花了幾章在抱怨目前大學課程(Java學校帶來的危害,耶魯大學的演講),相信能進去他的公司都是數一數二的高手。

其中有幾章作者特別替微軟的IE還有Office的格式做出解釋,還蠻值得一看得,有些東西真的是因為有歷史包袱在,結果就是現在使用者看到的這樣。



2012年2月22日 星期三

松本行弘的程式世界:成為一流程式設計師的14種思考術


這本書是Ruby的開發者Matz所寫得書。第一眼看到可能會覺得是Ruby的教學書,但其實這完全不是一本Ruby教學書。本書主要是以開發一個程式語言的角度來探討一些程式上的問題,作者並以Ruby的角度來講解如何解決這些問題並和其他程式語言做比較。比如說講到多重繼承,作者先探討多重繼承在C++和Java的設計上分別會有那些問題,最後再講解為什麽Ruby要使用Mix-in來實做多重繼承。

當然還有很多其他的內容,比如說探討Design Pattern,作者就用Ruby示範了一些Pattern的實做,有些Pattern改用Ruby這種動態語言來實做會變得非常直覺好懂。其他包含MVC, Unicode, Regular Expression, Floating Point......作者一開始都先簡單講解其他語言的設計方法,最後再說明為什麽Ruby要這樣設計,看完以後會覺得Ruby真的實做了很多新的東西,並且吸收了其他程式語言好得設計方式。

看這本書前其實不太需要先學會Ruby,作者在用Ruby寫範例Code的時候都會順便解釋Ruby的語法,像我本身並不會Ruby,但是大部分範例都可以看得懂。如果你是像我一樣對如何設計一個程式語言很有興趣的話,這本書是市面上少見在探討語言本身性質的書,非常值得一看!

2012年1月20日 星期五

[Python]named tuple

在Python裡頭有一個很好用的container叫做named tuple,他可以用來建立一個自己定義的class並且具有原本tuple的所有功能
這樣說可能有點難懂,以下是一個實際使用的例子:

Point = collections.namedtuple("Point", "x y")

collections.namedtuple()的第一個參數是自己定義的class名稱。第二個參數則是class中有的data名稱所組成的字串
由空格隔開不同的data名稱。當呼叫此function後,會回傳一個自己定義的class
我們就可以把他當作其他Python常見的class來使用(ex: list)
在此範例中,定義了一個namedtuple()幫我們建立了一個Point的class,其中有x和y這兩個data member
因此可以這樣使用他:
p = Point(100, 200)
print(p.x, p.y)
Output:
100, 200

named tuple的作法是去繼承tuple,並根據使用者給的參數產生出一個新的class,因此原本tuple的功能也可以在named tuple中使用
x, y = p         # unpack like a regular tuple

named tuple有幾個好用的地方,比如說從資料庫、csv檔的時候,可以直接讀到我們自己定義的named tuple中
EmployeeRecord = namedtuple('EmployeeRecord', 'name, age, title, department, paygrade')

import csv
for emp in map(EmployeeRecord._make, csv.reader(open("employees.csv", "rb"))):
    print(emp.name, emp.title)

或是從檔案讀入資料,下列範例從檔案讀取資料經過處理後存到用named tuple自己定義的User class中
User = collections.namedtuple("User", "username hashed_password id")
users = []
for line in open(filename):
    fields = line.split(":")
    user = User(fields[USERNAME], fields[HASHED_PASSWORD], fields[ID]) 
    users.append(user)

使用named tuple會直接套用預設的class template產生簡單的class,此方法讓程式碼可讀性提高很多
使用起來也相當便利,省去了自己宣告class定義資料型態所花的時間

Clean Code: A Handbook of Agile Software Craftsmanship

Clean Code,看到書名就知道這是一本教你如何寫出乾淨且容易維護程式碼的一本書。這本書一開始先從最基本的命名開始講起,接著講到怎麼寫出漂亮乾淨的function以及如何撰寫好的註解。最後還講到了例外處理、Class以及Unit Test要注意的事項。

我覺得寫程式分幾種境界,一開始初學者的時候只要想辦法把程式寫出來就好了。但是變成老手之後,要把程式寫出來變得不是那麼困難。困難的地方反而是如何寫出乾淨且容易維護程式碼。大部份的人都可以寫出電腦看得懂的程式,只有高手才能寫出乾淨簡潔、讓其他人很容易看懂的程式碼。這本書介紹了很多技巧幫助程式設計師能寫出Clean Code,很推薦學程式有一段時間的人去閱讀這本書。

書中有提到一些重要的觀念,比如說強調命名的重要性、function要盡量簡短、盡量用程式碼來解釋程式而不是註解、不要害怕重構。看完以後收穫很多。可惜這本書目前只有英文版,而且作者有用到一些艱深的單字。不知道未來會不會有中譯本出現(補充: 已經有國內出版社推出中譯本)。

以下是一些我的讀書筆記,大家可以參考看看