python入門系列(3) -- python語言基礎語法
本章主要根據 “python manual”(在安裝python後附帶)中的Tutorial簡化整理而來。有時間可以檢視官方原來的文件。遇到模組或函式不清楚的也可以查詢Manual。
內建資料型別
和大多數動態語言一樣,python中的變數是動態變數,所以定義時不需要指定變數型別,只跟實際賦值時有關(python的所有變數都是物件)。
numbers(數字)
數字的使用跟數學表示式一樣
>>> (50-5*6)/4 # 數學表示式
5
>>> 7/3 # 預設返回floor
2
>>> 7/-3
-3
>>> 7/3.0 # 浮點數
2.3333333333333335
變數賦值
>>> width = 20
>>> x = y = z = 10 # 變數可以同時賦值
>>> x,y = 100,200 # 多個賦值
>>> print x, y
100 200
進位制轉換
>>> a=100
>>> hex(a) # 十六進位制
'0x64'
>>> oct(a) # 八進位制
'0144'
ascii碼轉換
>>> ord('a') # 字母轉數值
97
>>> chr(97) # 數值轉字母
'a'
string(字串)
python通過單引號、雙引號或三重引號引起來的表示字串。在這裡,使用單引號和雙引號完全是一樣的,使用單引號做引用,字串中可以雙引號字元;使用雙引號,字串中可以包含單引號,否則,需要加轉義字元
>>> 'doesn\'t'
"doesn't"
>>> "doesn't"
"doesn't"
>>> '"Yes," he said.'
'"Yes," he said.'
>>> "\"Yes,\" he said."
'"Yes," he said.'
>>> '"Isn\'t," she said.'
'"Isn\'t," she said.'
跨行引用,則需要和用 \n
和 \
連線字元
>>> print "Usage: thingy [OPTIONS]\n\
-h Display this usage message\n\
-H hostname Hostname to connect to"
Usage: thingy [OPTIONS]
-h Display this usage message
-H hostname Hostname to connect to
使用三重引號,"""
或 '''
,可以更方便地跨行字串
>>> print """
Usage: thingy [OPTIONS]
-h Display this usage message
-H hostname Hostname to connect to
"""
Usage: thingy [OPTIONS]
-h Display this usage message
-H hostname Hostname to connect to
原始字串,通過在字串前面加字母r,表示字串是raw string,不會對字串中的字元進行轉義
>>> print r"""aaaaaaaa\nbbbb"""
aaaaaaaa\nbbbb
字串可以通過+號進行連線,通過*號進行重複
>>> word = 'Help' + 'A'
>>> word
'HelpA'
>>> '<' + word*5 + '>'
'<HelpAHelpAHelpAHelpAHelpA>'
字串採用和C的一樣的索引方式,下標從0開始。同時,子串可以使用分片的記法,冒號左邊為開始字元的下標,右邊為結束字元下標+1
>>> word[4]
'A'
>>> word[0:2]
'He'
>>> word[2:4]
'lp'
分片記法還用兩個方便的預設值,左邊預設為0,右邊預設為整個字串長度
>>> word[:2] # The first two characters
'He'
>>> word[2:] # Everything except the first two characters
'lpA'
分片記法,還可以使用負數下標,表示
>>> word[-1] # The last character
'A'
>>> word[-2] # The last-but-one character
'p'
>>> word[-2:] # The last two characters
'pA'
>>> word[:-2] # Everything except the last two characters
'Hel'
取子字串時,如果超過範圍,會被自動擷取
>>> word[-100:200]
'HelpA'
字串還可以步進式地擷取字元。如:
>>> word[::2]
'HlA
>>> word[::-1] # 倒序輸出
'ApleH'
上面主要介紹字串的擷取和拼接,字串其他常用操作如下:
- 去左右空白字元或特殊字元
>>> " aaaa ".strip() # 去左右空白字元
aaaa
>>> " aaaa ".rstrip() # lstrip去左側空格,rstrip去右側空格
aaaa
>>> " aaaa,,,...".rstrip(',.!') # 去指定字元
' aaaa'
- 取字串長度
>>> len(word)
5
- 定位字元或子串
>>> "aaabbbccc".index('bb')
3
>>> "aaabbbccc".index('bc')
5
- 比較字串
>>> cmp('aa','bb')
-1
>>> cmp('aa','aa')
0
>>> cmp('bb','aa')
1
- 字串大小寫轉換
>>> 'aaa'.upper()
'AAA'
>>> 'Aaaa'.lower()
'aaaa'
- 字串查詢
>>> 'aaabbbccc'.find('bbb')
3
index如果沒找到會丟擲異常,find沒找到返回-1
- 字串替換
>>> "aaabbbaaadddd".replace('a', 'e')
'eeebbbeeedddd'
>>> "aaabbbaaadddd".replace('aaa', 'e')
'ebbbedddd'
- 字串分割
>>> "aaaaa;;bbb;;ccc;ddd;".split(';;')
['aaaaa', 'bbb', 'ccc;ddd;'] # 字串陣列
>>> "aaaaa;bbb;ccc;ddd;".split(';')
['aaaaa', 'bbb', 'ccc', 'ddd', '']
- 合併字串
>>> ''.join(['aaaa', 'bbb', 'ccc'])
'aaaabbbccc'
>>> ';'.join(['aaaa', 'bbb', 'ccc'])
'aaaa;bbb;ccc'
python的字串是不可修改的。如修改一個字元,應使用replace,或使用左邊字串+新字元+右邊字串拼接而成
list(陣列)
python使用如下語法定義list,list的元素型別可以不一樣
>>> a = ['spam', 'eggs', 100, 1234]
>>> a
['spam', 'eggs', 100, 1234]
list訪問的分片記法與字串相似,而且一樣使用+進行連線,*
進行重複
>>> a[1:-1]
['eggs', 100]
>>> a[:2] + ['bacon', 2*2]
['spam', 'eggs', 'bacon', 4]
>>> 3*a[:3] + ['Boo!']
['spam', 'eggs', 100, 'spam', 'eggs', 100, 'spam', 'eggs', 100, 'Boo!']
與字串不同,python的list是可以修改的
>>> letters = ['a', 'b', 'c', 'd', 'e', 'f', 'g']
>>> # replace some values
>>> letters[2:5] = ['C', 'D', 'E']
>>> letters
['a', 'b', 'C', 'D', 'E', 'f', 'g']
>>> # now remove them
>>> letters[2:5] = []
>>> letters
['a', 'b', 'f', 'g']
返回list大小
>>> a = ['a', 'b', 'c', 'd']
>>> len(a)
4
list可以巢狀,構造多維陣列
>>> p=['a', 'b']
>>> p2=['a', p, 'b']
>>> p2
['a', ['a', 'b'], 'b']
list其他常用操作:
- append(x) 新增一個元素到末尾
- extend(x) 相當於+
- insert(i, x) 在i插入x
- remove(x) 刪除x
- pop() 彈出
- index(x) 返回第一個匹配x的下標
- count(x) 返回匹配x的個數
- sort(cmp=None, key=None, reverse=False) 排序
- reverse() 生成反序陣列
注意append和+的區別,append一個數組,是把陣列當成一個元素新增進去,+陣列是把所有元素新增進去
list還提供了一種叫做 list comprehensions
方法可以從一個list產生新的list,它參照了函數語言程式設計中的filter-map-reduce的思想[參考第5章]
>>> l=range(10)
>>> l
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> [x**2 for x in l if x%2] # 返回list中奇數的平方
[1, 9, 25, 49, 81]
tuple(元組)
tuple由多個值和逗號組成,前後可加括號,也可以不加
>>> t = 12345, 54321, 'hello!'
>>> t[0]
12345
>>> t
(12345, 54321, 'hello!')
>>> (a,b) = (2, 3)
>>> c,d = 1, (2, 3)
>>> len(d)
2
與list不同,tuple是不可修改的,所以不能修改tuple中的資料。tuple一般在賦值、列印或pack,unpack時使用。tuple列印的例子
>>> print "Hello, %s, %s, %s" % ('1', '2', '3') #此時tuple需要加()否則語法錯誤
set(集合)
set是無序的,元素不重複的collection。主要用於成員檢測和消除重複元素。集合可以由大括號、陣列、字串來生成。集合還支援並集、交集、差集等操作
>>> a={1, 2, 2, 2, 3}
>>> a
set([1, 2, 3])
>>> set(['1','2','2','3'])
set(['1', '3', '2'])
>>> 'orange' in fruit # fast membership testing
True
>>> # Demonstrate set operations on unique letters from two words
...
>>> a = set('abracadabra')
>>> b = set('alacazam')
>>> a # unique letters in a
set(['a', 'r', 'b', 'c', 'd'])
>>> a - b # letters in a but not in b
set(['r', 'd', 'b'])
>>> a | b # letters in either a or b
set(['a', 'c', 'r', 'd', 'b', 'm', 'z', 'l'])
>>> a & b # letters in both a and b
set(['a', 'c'])
>>> a ^ b # letters in a or b but not both
set(['r', 'd', 'b', 'm', 'z', 'l'])
dictionary(字典)
dictionary是無序的,鍵值對集合
>>> tel = {'jack': 4098, 'sape': 4139}
>>> tel['guido'] = 4127
>>> tel
{'sape': 4139, 'guido': 4127, 'jack': 4098}
>>> tel['jack']
4098
>>> del tel['sape']
>>> tel['irv'] = 4127
>>> tel
{'guido': 4127, 'irv': 4127, 'jack': 4098}
>>> tel.keys()
['guido', 'irv', 'jack']
>>> 'guido' in tel
True
>>> dict([('sape', 4139), ('guido', 4127), ('jack', 4098)])
{'sape': 4139, 'jack': 4098, 'guido': 4127}
如果key是簡單的字串, dict也可以這樣構造
>>> dict(sape=4139, guido=4127, jack=4098)
{'sape': 4139, 'jack': 4098, 'guido': 4127}
del操作可用於list, set, dictionary等可變的結構中,用於刪除元素
其他型別
其他型別還有
- None 空值
- True 為真的布林型別
- False 為假的布林型別
- deque 佇列,需要import collections
- nametuple 命名tuple
表示式
python中的表示式有以下特點:
- 語句不需要以
;
結束,不同的語句需要換行 - 語法塊(if,while,for,defun,class等)不是通過加大括號來確定範圍,而是用:加對程式碼對齊的方式來確定,python通過語法強制對齊的方式,讓程式碼更可讀,如下面if程式碼塊的例子
>>> # 加:,程式塊多條語句用tab或空格對齊
>>> if 1>2:
print '1'
print '2'
>>> # 沒對齊導致語法錯誤
>>> if 1>2:
print '1'
print '2'
File "<pyshell#38>", line 3
print '2'
^
IndentationError: unexpected indent
- 通過#號進行註釋
- 空語句 pass
控制流
條件判斷
條件判斷語法很簡單,if…elif…else,如下
>>> x = int(raw_input("Please enter an integer: "))
Please enter an integer: 42
>>> if x < 0:
print 'Negative'
elif x == 0:
print 'Zero'
else:
print 'Positive'
Positive
條件除了比較,還可以是一些操作。in和not in用來判斷元素是否在序列中(list,tuple,set,string,dictionary等), is和not is用來判斷元素是否是相同的物件
>>> '1' in ['1', '2', '3']
True
>>> '1' in ('1','2','3')
True
>>> '1' in {'1','2','3'}
True
>>> '1' in {'1':1, '2':1}
True
對物件的判斷,如果物件不是None型別的,就返回True
>>> if not None:
print "It's True"
It's True
複合條件有not, and, or, not的優先順序最高, or的優先順序最低, and和or的求值是採用正則序的,即從左到右判斷條件,有需要判斷時才會對某個條件表示式進行求值,and時一旦有個條件為False,或or時一旦有條件為True,後面的條件判斷不會進行下去了。and或or的返回值是最後一個進行求值的條件表示式值
>>> string1, string2, string3 = '', 'Trondheim', 'Hammer Dance'
>>> non_null = string1 or string2 or string3
>>> print non_null
Trondheim
不像c語言,python無法在條件判斷中賦值。這樣可以避免==和=易寫錯的情況
迭代
使用while進行迭代, continue, break等用法與C類似
i=0
while i<3:
if i%2:
print 'Odd:%d' % i
else:
pass
i=i+1
while中的條件表示式與if中的相同。
使用for進行迭代,一般使用for…in sequence的語法,sequence可以是list,dictionary等
>>> a = ['Learn', 'python']
>>> for i in range(len(a)):
print i, a[i]
0 Learn
1 python
>>> for v in a:
print v
>>> d={'a':100, 'b':200}
>>> for key,value in d.items():
print key,value
range用於生成list,一般用於遍歷
>>> range(10)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> range(1, 11)
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> range(0, 30, 5)
[0, 5, 10, 15, 20, 25]
>>> range(0, 10, 3)
[0, 3, 6, 9]
>>> range(0, -10, -1)
[0, -1, -2, -3, -4, -5, -6, -7, -8, -9]
上面還提到, list等sequence一般都提供了comprehensions,使用for和表示式生成新的sequence
>>> [x**3 for x in range(1,3)]
[1, 8]
>>> [(x, y**3) for x in range(1,3) for y in range(1,3)] # 兩層迴圈
[(1, 1), (1, 8), (2, 1), (2, 8)]
>>> {x: x**2 for x in (2, 4, 6)}
{2: 4, 4: 16, 6: 36}
>>> a = {x for x in 'abracadabra' if x not in 'abc'}
>>> a
set(['r', 'd'])
函式
使用def關鍵字定義函式,函式的引數,返回值與C類似, return語句沒帶值返回None,沒有return語句,也返回None
>>> def fib2(n): # return Fibonacci series up to n
"""Return a list containing the Fibonacci series up to n."""
result = []
a, b = 0, 1
while a < n:
result.append(a) # see below
a, b = b, a+b
return result
>>> f100 = fib2(100) # call it
>>> f100 # write the result
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
函式和C++一樣,可以帶預設引數。預設引數可以是當前已知的變數
i=5
def f(arg=i):
print arg
f()
i = 6
f()
預設引數只求值一次,所以上面兩個f呼叫產生的結果一致.
引數還可以使用keyword的方式賦值
def parrot(voltage, state='a stiff', action='voom', type='Norwegian Blue'):
print "-- This parrot wouldn't", action,
print "if you put", voltage, "volts through it."
print "-- Lovely plumage, the", type
print "-- It's", state, "!"
parrot(1000) # 1 positional argument
parrot(voltage=1000) # 1 keyword argument
parrot(voltage=1000000, action='VOOOOOM') # 2 keyword arguments
parrot(action='VOOOOOM', voltage=1000000) # 2 keyword arguments
parrot('a million', 'bereft of life', 'jump') # 3 positional arguments
parrot('a thousand', state='pushing up the daisies') # 1 positional, 1 keyword
注意下面幾種情況是非法的
parrot() # required argument missing
parrot(voltage=5.0, 'dead') # non-keyword argument after a keyword argument
parrot(110, voltage=220) # duplicate value for the same argument
parrot(actor='John Cleese') # unknown keyword argument
函式支援變參, 定義函式時,一個 *
號是多個引數列表, 兩個 *
號引數按字典解析
def cheeseshop(kind, *arguments, **keywords):
print "-- Do you have any", kind, "?"
print "-- I'm sorry, we're all out of", kind
for arg in arguments:
print arg
print "-" * 40
keys = sorted(keywords.keys())
for kw in keys:
print kw, ":", keywords[kw]
cheeseshop("Limburger", "It's very runny, sir.",
"It's really very, VERY runny, sir.",
shopkeeper='Michael Palin',
client="John Cleese",
sketch="Cheese Shop Sketch")
它將列印
-- Do you have any Limburger ?
-- I'm sorry, we're all out of Limburger
It's very runny, sir.
It's really very, VERY runny, sir.
----------------------------------------
client : John Cleese
shopkeeper : Michael Palin
sketch : Cheese Shop Sketch
呼叫函式時,也可以使用類似的 *
號標記來unpack引數列表或字典
>>> range(3, 6) # normal call with separate arguments
[3, 4, 5]
>>> args = [3, 6]
>>> range(*args) # call with arguments unpacked from a list
[3, 4, 5]
unpack字典引數
>>> def parrot(voltage, state='a stiff', action='voom'):
... print "-- This parrot wouldn't", action,
... print "if you put", voltage, "volts through it.",
... print "E's", state, "!"
...
>>> d = {"voltage": "four million", "state": "bleedin' demised", "action": "VOOM"}
>>> parrot(**d)
-- This parrot wouldn't VOOM if you put four million volts through it. E's bleedin' demised !
- lambda表示式
小的匿名函式可以使用lambda表示式代替(lambda表示式是函數語言程式設計中的重要思想)
>>> def make_incrementor(n):
return lambda x: x + n
>>> f = make_incrementor(42)
>>> f(0)
42
>>> f(1)
43
上面使用lambda返回一個函式,另一種表示是把lambda函式當引數
>>> pairs = [(1, 'one'), (2, 'two'), (3, 'three'), (4, 'four')]
>>> pairs.sort(key=lambda pair: pair[1])
>>> pairs
[(4, 'four'), (1, 'one'), (3, 'three'), (2, 'two')]
語言如果使用lambda,一般都要涉及區域性變數(狀態),函式作為引數等概念,在一些函數語言程式設計語言中,函式只是lambda的語法糖,即函式只是命了名的lambda表示式。
在sicp中提到可以使用過程來代替資料結構,來達到程式碼和資料的優雅統一。如
#使用過程來代替資料結構--序對
def cons(x,y):
return lambda m: m and x or y
#取第一個數
def car(z):
return z(1)
# 取第二個數
def cdr(z):
return z(0)
d=cons(100, cons(1000, 10000))
print car(d), car(cdr(d)), cdr(cdr(d))
上面例子中,通過使用返回的lambda,定義了序對資料結構,通過cons構造,car和cdr來取序對的值,從而實現了一個基礎的
資料結構(lisp系的資料全是基於list的,而list又可以用序列表示),而不用任何定義結構體的語句(這就是函數語言程式設計語法簡單的一個例子)。
python支援自省,就是說可以在函式,類的定義中加入文件
>>> def my_function():
... """Do nothing, but document it.
...
... No, really, it doesn't do anything.
... """
... pass
...
>>> print my_function.__doc__
Do nothing, but document it.
No, really, it doesn't do anything.
python模組
python中每個py檔案就是一個模組。每個模組中有個全域性變數name標誌模組名。在別的模組呼叫一個模組時,使用import語法,如在fibo.py中輸入以下函式
def fib(n): # write Fibonacci series up to n
a, b = 0, 1
while b < n:
print b,
a, b = b, a+b
def fib2(n): # return Fibonacci series up to n
result = []
a, b = 0, 1
while b < n:
result.append(b)
a, b = b, a+b
return result
然後,在另一個檔案可以這樣呼叫
import fibo
fibo.fib(1000)
import還存在另一種寫法, 它把函式直接匯入發起匯入的模組的符號表中
>>> from fibo import fib, fib2
>>> fib(500) # 不需要再加模組名了
1 1 2 3 5 8 13 21 34 55 89 144 233 377
或者全部匯入
>>> from fibo import *
>>> fib(500)
1 1 2 3 5 8 13 21 34 55 89 144 233 377
當你使用
python fibo.py <arguments>
時,name被自動設定為”main“,所以你可以在py中加入如下的判斷
if __name__ == "__main__":
import sys
fib(int(sys.argv[1]))
那麼py即可以直接呼叫,也可以在別的模組中被引用。
python的模組搜尋目錄存在sys.path變數中,預設值包括三個:
- 當前目錄
- PATH系統目錄
- python的安裝目錄
>>> import sys
>>> print sys.path
['', 'C:\\Python27\\Lib\\idlelib', 'C:\\Python27\\lib\\site-packages\\setuptools-14.0-py2.7.egg', 'C:\\Python27\\lib\\site-packages\\sphinx-1.3b3-py2.7.egg', 'C:\\Python27\\lib\\site-packages\\colorama-0.3.3-py2.7.egg', 'C:\\Python27\\lib\\site-packages\\sphinx_rtd_theme-0.1.6-py2.7.egg', 'C:\\Python27\\lib\\site-packages\\alabaster-0.7.1-py2.7.egg', 'C:\\Python27\\lib\\site-packages\\babel-1.3-py2.7.egg', 'C:\\Python27\\lib\\site-packages\\pytz-2014.10-py2.7.egg', 'C:\\Python27\\lib\\site-packages\\pip-6.0.8-py2.7.egg', 'C:\\Windows\\system32\\python27.zip', 'C:\\Python27\\DLLs', 'C:\\Python27\\lib', 'C:\\Python27\\lib\\plat-win', 'C:\\Python27\\lib\\lib-tk', 'C:\\Python27', 'C:\\Python27\\lib\\site-packages']
>>> sys.path.append('/ufs/guido/lib/python')
- 使用dir來獲取模組資訊
>>> import fibo, sys
>>> dir(fibo)
['__name__', 'fib', 'fib2']
>>> dir(sys)
['__displayhook__', '__doc__', '__excepthook__', '__name__', '__package__',
'__stderr__', '__stdin__', '__stdout__', '_clear_type_cache',
'_current_frames', '_getframe', '_mercurial', 'api_version', 'argv',
'builtin_module_names', 'byteorder', 'call_tracing', 'callstats',
'copyright', 'displayhook', 'dont_write_bytecode', 'exc_clear', 'exc_info',
'exc_traceback', 'exc_type', 'exc_value', 'excepthook', 'exec_prefix',
'executable', 'exit', 'flags', 'float_info', 'float_repr_style',
'getcheckinterval', 'getdefaultencoding', 'getdlopenflags',
'getfilesystemencoding', 'getobjects', 'getprofile', 'getrecursionlimit',
'getrefcount', 'getsizeof', 'gettotalrefcount', 'gettrace', 'hexversion',
'long_info', 'maxint', 'maxsize', 'maxunicode', 'meta_path', 'modules',
'path', 'path_hooks', 'path_importer_cache', 'platform', 'prefix', 'ps1',
'py3kwarning', 'setcheckinterval', 'setdlopenflags', 'setprofile',
'setrecursionlimit', 'settrace', 'stderr', 'stdin', 'stdout', 'subversion',
'version', 'version_info', 'warnoptions']
異常
捕獲異常
python的捕獲異常語法,如下例子
try:
code_block()
except SomeException, e:
do_some_thing_with_exception(e)
except (Exception1, Exception2), e:
do_some_thing_with_exception(e)
except:
do_some_thing_with_other_exceptions()
else:
do_some_thing_when_success()
finally:
do_some_thing()
其中,except可以使用else分支,來匹配try執行無異常的情況, finally是不管有無異常都會執行。
python2.7.x和python3.x的異常語法不太一樣。
丟擲異常
python使用raise來丟擲異常
try:
raise NameError, 'HiThere'
except NameError, a:
print 'An exception flew by!'
print type(a)
raise 函式的第一個引數是異常名,第二個是這個異常的例項,它儲存在 instance.args 的參
數中。和 except NameError, a: 中的第二個引數意思差不多。