跳轉到內容

數值方法入門/Python 程式設計

來自華夏公益教科書,開放的書籍,開放的世界

Python 程式設計

[編輯 | 編輯原始碼]

目標

  • 熟悉 Python 程式語言和命令列介面
    • 使用正確的控制結構
    • 用正確的語法編寫簡單的 Python 程式
  • 匯入和使用庫

資源

Python 是一種指令碼語言。您可以使用互動式 Python 控制檯來編寫和執行程式碼。登入 Unix/Linux 系統後,您可以鍵入 "python"(帶引號)啟動控制檯,然後按 ^D(ctrl+D)退出控制檯。這種互動性使其非常適合探索性發現 - 透過探索和實驗找到解決方案。

Python 控制檯執行一個讀取-求值-列印迴圈 (REPL),這意味著它會提示您輸入表示式/命令,一旦您按下回車鍵,它就會讀取您的表示式,對其進行求值,打印表達式的值,並提示您輸入下一個表示式。這使得測試 Python 語句變得非常容易。您可以將其用作計算器

>>>1+2
3
>>>2**3
8
>>> # this is a comment
...
>>> 2**0.5
1.4142135623730951

匯入庫

[編輯 | 編輯原始碼]

許多有用的函式已在庫中實現。要使用這些函式,您需要匯入它們,以便識別它們的名稱。dir() 函式列印模組中可用物件的目錄(函式)

>>>import math
>>>dir(math)
['__doc__', '__name__', '__package__', 'acos', 'acosh', 'asin', 'asinh', 'atan', 'atan2', 'atanh', 'ceil', 
'copysign', 'cos', 'cosh', 'degrees', 'e', 'erf', 'erfc', 'exp', 'expm1', 'fabs', 'factorial', 'floor', 'fmod', 
'frexp', 'fsum', 'gamma', 'hypot', 'isinf', 'isnan', 'ldexp', 'lgamma', 'log', 'log10', 'log1p', 'modf', 
'pi', 'pow', 'radians', 'sin', 'sinh', 'sqrt', 'tan', 'tanh', 'trunc']
>>> help(math.exp)
Help on built-in function exp in module math:
exp(...)
    exp(x)
    
    Return e raised to the power of x.
>>> # this is similar to 2 ** 0.5
>>> math.sqrt(2)
1.4142135623730951

help() 函式可用於查詢庫中物件的含義和用法,如前面的程式碼示例所示。請注意,您需要按字母 Q 退出幫助會話以返回到 Python 控制檯。

資料型別

[編輯 | 編輯原始碼]

Python 不是強型別語言,這意味著您不需要為變數宣告特定的資料型別。但是與變數關聯的資料項具有型別,這些型別是隱式的 - 從表示式或對資料項的操作派生。因此,變數的資料型別可能會隨著時間的推移而改變。type() 函式將告訴您儲存在變數中的資料型別。

>>> type(a)
<type 'int'>
>>> type(1)
<type 'int'>
>>> a = 1.0
>>> type(a)
<type 'float'>
>>> a = "one"
>>> type(a)
<type 'str'>
>>> a = False 
>>> print a False
>>> type(a)
<type bool>
>>> a = 1 + 2j
>>> type(a)
<type 'complex'>
>>> a = [1, 2, 3]
>>> type(a)
<type 'list'>

有一些函式可以在資料型別之間進行轉換,例如 int()、float()、str() 和 list()。

>>> a = int("123")
>>> a
123
>>> type(a)
<type 'int'>
>>> a = float("123.4")
>>> a
123.4
>>> type(a)
<type 'float'>
>>> a = str(123.4)
>>> a
'123.4'
>>> type(a)
<type 'str'>
>>> a =  list("one two three")
>>> a
['o', 'n', 'e', ' ', 't', 'w', 'o', ' ', 't', 'h', 'r', 'e', 'e']
>>> type(a)
<type 'list'>

資料型別會根據需要自動提升。

>>> import sys
>>> sys.maxint
9223372036854775807
>>> type(sys.maxint)
<type 'int'>
>>> type(sys.maxint+1)
<type 'long'>

在 Python 中,字串、列表和元組是序列。它們可以像索引和切片一樣被索引和切片。Python 中的列表可以包含不同型別的資料項。

>>> range(10)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> for i in range(10):
...     print i ** 2
... 
0
1
4
9
16
25
36
49
64
81

原始檔

[編輯 | 編輯原始碼]

除了直接在控制檯中編寫和執行 Python 程式碼之外,您還可以將命令/語句儲存在檔案中,並使用 Python 直譯器執行整個檔案作為指令碼。例如,在 shell 命令列中,您可以鍵入以下內容來執行名為 hello.py 的程式/指令碼

python hello.py

縮排在 Python 中很重要,因為它用於定義作用域,從而消除了對大括號 {} 的使用。請確保同一級別的程式碼縮排量相同,用製表符或空格字元表示。

格式化列印

[編輯 | 編輯原始碼]

您可以使用類似於 C 中的 printf 函式的格式字串來列印數字。

>>>a = 0.1
>>> a
0.1
>>>print "%20.19f" % a
0.1000000000000000056

此示例顯示了浮點數表示的限制。1/10 無法精確表示,因為它不是 2 的冪。即使控制檯將 a 列印為 0.1,但底層表示也幾乎是 0.1。

數值計算

[編輯 | 編輯原始碼]
>>> import math
>>> a = math.sqrt(2)
>>> a
1.4142135623730951
>>> a ** 2
2.0000000000000004

以下示例將無限迴圈,直到結果溢位暫存器,因為 x 永遠不會完全變為 1.0,因為 0.1 的表示是一個近似值(存在誤差)。

>>> x = 0.0
>>> while not x == 1.0:
...     x = x + 0.1 
...     print("x=%19.17g" % (x))
... 
x=0.10000000000000001
x=0.20000000000000001
x=0.30000000000000004
x=0.40000000000000002
x=                0.5
x=0.59999999999999998
x=0.69999999999999996

教訓的寓意是:不要比較浮點數是否嚴格相等。或者,我們可以計算兩個數字之間的距離,並在距離足夠短時停止(小於閾值)。

>>> x = 0.0
>>> while abs(x - 1.0) > 1e-8:
...     x = x + 0.1
...     print("x=%19.17g" % (x))
... 
x=0.10000000000000001
x=0.20000000000000001
x=0.30000000000000004
x=0.40000000000000002
x=                0.5
x=0.59999999999999998
x=0.69999999999999996
x=0.79999999999999993
x=0.89999999999999991
x=0.99999999999999989

如果我們知道要執行多少次迭代,我們可以使用如下所示的 for 迴圈。請注意,range(1, 11) => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]。

>>> for i in range(1, 11):
...     x = i * 0.1
...     print("x=%19.17g" % (x))
... 
x=0.10000000000000001
x=0.20000000000000001
x=0.30000000000000004
x=0.40000000000000002
x=                0.5
x=0.60000000000000009
x=0.70000000000000007
x=0.80000000000000004
x=0.90000000000000002
x=                  1

以下程式碼片段計算了什麼?迴圈會結束嗎?為什麼?

>>> eps = 1.0
>>> while 1.0 + eps > 1.0:
...     eps = eps / 2.0
... 
>>> print eps
1.11022302463e-16

eps 的值將始終是 2 的冪,因此不會有任何舍入誤差。但是,隨著 while 迴圈的繼續,eps 會越來越小。最終 eps 會變得非常小,以至於與 1.0 相比幾乎為零,這意味著將其新增到 1.0 將導致 1.0。回想一下,機器精度是在新增到 1.0 時會導致不同於 1.0 的值的最小值。如果一個數字小於機器精度,則將其新增到 1.0 時不會產生任何影響。sys.float_info 告訴我們機器精度為 2.220446049250313e-16,略小於 2x1.11022302463e-16=2.22044604926e-16。這就是為什麼當迴圈結束時 eps 等於 1.11022302463e-16 的原因。

符號計算

[編輯 | 編輯原始碼]

Python 的 SymPy 庫允許我們以符號方式(作為符號)操作變數。以下程式碼片段演示了 SymPy 的一些基本功能。

>>> from sympy import Symbol
>>> x = Symbol('x');
>>> x+2*x+3*x
6*x
>>> y=x+2*x+3*x
>>> y
6*x
>>> y.subs(x, 2)
12
>>> from sympy import diff
>>> diff(y, x)
6
>>> from sympy import sin, cos
>>> diff(sin(x), x)
cos(x)
>>> diff(cos(x), x)
-sin(x)
>>> y = 4 - 1/x
>>> y.diff()
x**(-2)
>>> y.diff().subs(x, 0.5)
4.00000000000000
>>> from sympy import series
>>> sin(x).series(x, 0)
x - x**3/6 + x**5/120 + O(x**6)
>>> sin(x).series(x, 0, 10)
x - x**3/6 + x**5/120 - x**7/5040 + x**9/362880 + O(x**10)

Numpy 陣列和線性代數

[編輯 | 編輯原始碼]

來源

Numpy 中的陣列是相同型別元素的多維表格。這些元素由正整數元組索引。Numpy 陣列的類名稱是 ndarray,也稱為陣列。每個陣列物件都有許多屬性

  • mdim:維度數
  • shape:一個整數元組,指示陣列在每個維度上的大小。具有 m 行和 n 列的矩陣將以 (m, n) 作為其形狀。
  • size:陣列中元素的總數。
  • dtype:陣列中元素的型別。

您可以在 Ubuntu 上安裝 numpy 和 scipy,如下所示

sudo apt-get install python-numpy python-scipy python-matplotlib python-sympy

可以使用不同的語法引用陣列中的元素,如以下示例所示。

>>> from numpy import *
>>> a = arange(15).reshape(3, 5)
>>> a
array([[ 0,  1,  2,  3,  4],
       [ 5,  6,  7,  8,  9],
       [10, 11, 12, 13, 14]])
>>> type(a)
<type 'numpy.ndarray'>
>>> a.shape
(3, 5)
>>> (rows, cols) = a.shape
>>> rows
3
>>> cols
5
>>> a.ndim
2
>>> a.size
15
>>> a[2, 3]
13
>>> a[2][3]
13
>>> a[-1]
array([10, 11, 12, 13, 14])
>>> a[-2]
array([5, 6, 7, 8, 9])
>>> a[-2:]
array([[ 5,  6,  7,  8,  9],                                                 
       [10, 11, 12, 13, 14]])
>>> a[2:]
array([[10, 11, 12, 13, 14]])  
>>> a[:-3]
array([], shape=(0, 5), dtype=int64)
>>> a[:]
array([[ 0,  1,  2,  3,  4],                                                 
       [ 5,  6,  7,  8,  9],                                                 
       [10, 11, 12, 13, 14]]) 
>>> a[1, ...]
array([5, 6, 7, 8, 9]) 
>>> a[:, 0]
array([ 0,  5, 10])

可以使用 array 函式從常規 Python 列表或元組建立 Numpy 陣列。陣列元素的型別取決於序列中元素的型別。

>>> a = array([[1, 2], [2, 3]])
>>> a
array([[1, 2],
       [2, 3]])
>>> a = array(((4, 5), (6, 7)))
>>> a
array([[4, 5],
       [6, 7]])
>>> a.dtype
dtype('int64')
>>>>>> b = array([(1.2, 1.3), (1.4, 1.5)])
>>> b
array([[ 1.2,  1.3],
       [ 1.4,  1.5]])
>>> b.dtype
dtype('float64')

NumPy 包含建立帶有預設值的陣列的函式。eye() 函式建立單位矩陣,identity() 函式執行類似的功能。copy 函式克隆陣列物件,包括它包含的資料。

>>> zeros((2, 3))
array([[ 0.,  0.,  0.],
       [ 0.,  0.,  0.]])
>>> ones((3, 4))
array([[ 1.,  1.,  1.,  1.],
       [ 1.,  1.,  1.,  1.],
       [ 1.,  1.,  1.,  1.]])
>>> empty((2, 3))
array([[  2.68156159e+154,   2.68156159e+154,   2.68156242e+154],
       [  2.68156159e+154,   2.68156159e+154,   2.68156159e+154]])
>>> eye(3, 3)
array([[ 1.,  0.,  0.],
       [ 0.,  1.,  0.],
       [ 0.,  0.,  1.]])
>>> identity(3, float)
array([[ 1.,  0.,  0.],
       [ 0.,  1.,  0.],
       [ 0.,  0.,  1.]])

NumPy 陣列上的算術運算為逐元素運算。乘積 * 運算子執行逐元素乘法。dot 函式執行矩陣乘法。

>>> a
array([[1, 2],
       [3, 4]])
>>> b = a.copy()
>>> b
array([[1, 2],
       [3, 4]])
>>> a*b
array([[ 1,  4],
       [ 9, 16]])
>>> dot(a, b)
array([[ 7, 10],
       [15, 22]])

NumPy 還包含許多基本的線性代數函式。

>>> from numpy.linalg import *
>>> a = array([[1.0, 2.0], [3.0, 4.0]])
>>> a
array([[ 1.,  2.],
       [ 3.,  4.]])
>>> a.transpose()
array([[ 1.,  3.],
       [ 2.,  4.]])
>>> inv(a)
array([[-2. ,  1. ],
       [ 1.5, -0.5]])
>>> y = array([[5.], [7.]])
>>> solve(a, y)
array([[-3.],
       [ 4.]])

IPython Notebook

[編輯 | 編輯原始碼]

IPython Notebook 是一種互動式環境,允許對您的 Python 命令進行編碼、執行和記錄。

資源

華夏公益教科書