跳转到内容

数值方法入门/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 命令进行编码、执行和记录。

资源

华夏公益教科书