2012 下半年, 想學一種新的程式設計語言嗎? 選擇 Python 吧!
學習一門新語言, 有兩種方式: 1. 懷空杯心態, 盡量使用該語言的地道表達方式, 避免受原有語言思路的影響; 2. 將新語言與原有語言關聯對比, 從而在最快時間內能夠掌握基礎知識,編寫出有用的程式。一般這種情況下,是項目需求所致。
學習Python 有如下理由: 1. 表達能力強大, 不遜於C,C++,JAVA這些主程式設計語言 這是必要條件; 2. 它是類指令碼語言, 這意味著簡化了程式的編寫, 用更少的程式碼完成用主程式設計語言可能文法繁瑣的各種任務; 3. 格式嚴謹, 有利於代碼風格的訓練和軟體代碼的可讀性,項目代碼的管理; 4. 庫、架構多,可以快速建立應用。 有此四條足矣,趕緊上路吧,別比來比去了!
我採用的思路是將 Python 與 Java 關聯起來, 學習 Python 基礎. 所以,本文不打算細述 Python 的文法, 而是通過對比差別來增強對Python 的認識, 當然, 大量的編程練習是必要的,最好能夠結合一個小項目,並通過不斷試錯。 我是通過公司的一個實際項目邊學邊用而學習使用 Python 的。
1. Python 的代碼縮排: 這是首先要提到的。 用括弧括起來的代碼塊, 將通過 冒號加 正確縮排(同一層次的代碼塊必須使用完全相同的縮排) 來表達 , 條件陳述式中的括弧通常可省略。 語句末的分號可有可無。寫python 代碼塊時一定要注意加上冒號和正確的縮排, 這是經常容易犯的錯誤。例如:
while ( i < 100) {
i += 2
printf("%d",x)
}
用 python 寫是這樣:
while i < 100 :
i += 2 // 這裡正確的縮排是必要的,否則報語法錯誤。
# print x ## Error: unexpected indent , 同一層次的代碼必須採用完全相同的縮排, 多一個或少一個空格都不行。
2. 變數在使用前一定要進行初始化和賦值,否則解譯器無法識別該變數。一個變數均可以儲存多種類型的值,不強調類型。 函數定義時不強調類型。 這是指令碼語言的特點, 方便程式的編寫。 比如
def func(x) :
return x*2
x = 2
y = func(x)
print x , " ", y
x = ' now changed to an string '
print x, " " , y , ' OMG' # 鬆散的列印格式 , 雙引號和單引號均可表示字串
# print zzz 會報錯: NameError : name 'zzz' is not defined.
3. 控制流程 : if , if-elif-...-else , for ... in ... , while , continue, break ; 還有一個 pass 語句表示空執行, 即相當於空塊,或者 NOP
4. 單行注釋用 # 號, 多行注釋用三個單引號
''' these are
more lines.
'''
5. 強大的內建動態資料結構: list , set, tuple, dictionary . 這些動態資料結構很容易組合成更強大的資料結構工具。 關於這些結構的使用,網上有很多文章,這裡就不細述了。
mylist = [ ] # 建立空列表
mylist = [1 , 3 , 'good']
print mylist
mylist[1] = [('this is a tuple'), ['nested list']]
print mylist
list 主要方法有: append(x) , extend(List), insert(x), sort(), reversed(), pop([i]), insert(i, x), 等。
myset = [1 , 2 ,1 ,1 , 2] # 建立集合 ===> myset = [1 ,2]
set 有成員檢測功能:
x = 1
if x in myset :
print myset, " has member : ", x
else :
print x , " is not found in ", myset
mydict = {1 : ('zs', 'good', 25) , 2 : ('ww', 'right', 30) }
print mydict
mydict['city'] = 'hangzhou'
for k, v in mydict.iteritems() :
print k, v
print dict.keys()
元組 tuple 與列表類似, 但元組是不可變的, 這意味著無法修改元組的值。 引用元組的值採用下標方式
mytuple = (1, 2, 3, 4)
print mytuple[2]
# Error : mytuple[0] = 0
6. 模組。 一個 python 檔案就是一個模組, 以 .py 為尾碼。 當你在 func.py 中編寫了函數 sign(x) 後, 要在其他檔案中引用,則採用如下方式:
[1] import func
func.sign(x) # 模組名.函數名
[2] from func import sign(x)
sign(x) # 直接引用
7. 範圍。 這裡主要給出一個基本的理解。 如上所述,
a. 一個 Python 檔案就是一個模組,該模組的變數的範圍主要可分為全域範圍,本地範圍以及內建範圍。
b. 代碼塊(例如, try塊,if-else, for , while 等),函數中定義的變數,方法,類等屬於本地範圍, 可以通過 locals() 查詢,作用範圍在建立時到代碼塊或函數退出為止; 函數之外的變數,方法,類等屬於全域範圍,作用範圍從建立時到整個檔案末尾為止,可以通過 globals() 查詢。
c. 當全域範圍的變數與本地範圍的變數衝突時,會優先採用本地範圍中的變數,尋找不到時再到全域範圍中尋找。要使用全域範圍的變數,必須先聲明 global var. 聲明global var 之前不能出現同名變數 var. 請看:
x = 2
def fun1() :
x = 3
print "[1] x = " , x // 使用局部變數x 列印 [1] x = 3
print "init: x = " , x // 使用全域變數x 列印 init x = 2
fun1()
print "after [1] x = ", x // 不會改變全域變數x 列印 after [1] x = 2
def fun2() :
global x // 聲明使用全域變數 x
x = 3
fun2()
print "after fun2 : x = ", x // 列印 after fun2: x = 3
def fun3() :
x = 0
#ERROR global x : 語法錯誤: x 不能既是全域變數又是局部變數。也就是說,
print "[3] x = ", x : 要使用全域變數,不可以出現在同名的局部變數之後。
fun3()
內建範圍是python 語言所定義的系統變數,方法,類等的範圍, 可以直接使用。 例如, type 函數可以列印對象的類型。
print type(x) // 列印 <type 'int'>
def type(x) :
print "my type(): "
return x*2
print type(x) // 列印 6
因此,可以得到又一條結論: 如果定義了與內建方法同名的方法, 會優先採用自訂的方法。 事實上, 範圍的優先順序:
本地範圍 》 全域範圍 》 內建範圍
8. 異常機制。 try-except , try-except-else, try-finally, try-except-finally 四種。
9. if __name__ == '__main__' : do something ; __name__ 是python模組的內建屬性。每個python模組都是一個.py檔案,既可以從命令列運行,又可以匯入其他模組。當從命令列運行時,__name__ == ‘__main__’ , do something 會執行; 當匯入其他模組時, __name__ 的值為模組的名稱, 不等於‘ __main__ ’, do something 不會執行。也就是說,該模組存在某些語句,當自身單獨運行時,期望被執行,而作為支援模組匯入其他模組時,卻不希望執行。
因此, 這條語句通常可用於單獨運行和測試該模組。
10. 下面的例子示範了Python 提供的一些基礎語言特性: 縮排,內建資料結構, 控制流程, 讀寫檔案,重新導向, 匯入模組, 類定義, 異常機制,日誌,Regex。代碼本身沒有什麼創新之處,但整合到一起,可以示範Python 的大部分基礎語言特性。
dupkeys.py
#################################################################### validate if the input text file contains duplicated keys.# the input.txt should like below:# key1 value1# key2 value2# ...## the result is stored into a hashtable:# {key: [count, [value1, value2,..,valueN]]} ###################################################################import sysimport refrom thelog import initlogfrom exc import NotMatchedExceptionpatt = re.compile(r'^\s*(\w+)\s+(\w+)[\s\r\n]+$')total_items = 0count = { }def proc(line) : matched = patt.match(line) try : if matched : global total_items total_items += 1 key = matched.group(1) value = matched.group(2) if key in count : valuelist = (count[key])[1] valuelist.append(value) count[key] = [(count[key])[0]+1, valuelist] else : count[key] = [1, [value]] else : raise NotMatchedException('The line Not matched: %s' % line) except (NotMatchedException, Exception), args: dupkeysLog.error(args)if len(sys.argv) != 2 : print "usage: python dupkeys.py filename.txt " sys.exit(1)logfile = 'dupkeys.log'dupkeysLog = initlog(logfile)resfile = open('result.txt', 'w')sysStdout = sys.stdoutsys.stdout = resfile # redirect stdout into file result.txt filename = sys.argv[1]inputfile = open(filename)for line in inputfile : proc(line)print "total items in file %s : %d" % (filename, total_items)dupkeysLog.error("Keys duplicated: ")for k, v in count.iteritems() : print k, v if v[0] > 1 : dupkeysLog.error( ' %s %s ' % (k, v) )if inputfile: inputfile.close()if resfile : resfile.close()sys.stdout = sysStdout
thelog.py
import loggingLOG_LEVELS = { 'DEBUG': logging.DEBUG, 'INFO': logging.INFO, 'WARN': logging.WARNING, 'ERROR': logging.ERROR, 'CRITICAL': logging.CRITICAL }def initlog(filename) : logger = logging.getLogger() hdlr = logging.FileHandler(filename) formatter = logging.Formatter("%(asctime)s %(levelname)s %(message)s") hdlr.setFormatter(formatter) logger.addHandler(hdlr) logger.setLevel(LOG_LEVELS['ERROR']) return loggerif __name__ == '__main__' : errlog = initlog("errlog.log") errlog.info('this is an ordinary info') errlog.warn('this is a warning') errlog.error('this is an error that should be handled') errlog.critical('this is an severe error')
exc.py
class MyException(Exception) : passclass MsgException(MyException) : def __init__(self, msg) : self.msg = msg def __str__(self) : return repr(self.msg)class NotMatchedException(MsgException) : pass