1. 程式人生 > >python入門系列(3) -- python語言基礎語法

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: 中的第二個引數意思差不多。

自定義異常