微分、積分、極限、級數;差分,線性方程組,微分方程;符號矩陣。
from IPython.core.interactiveshell import InteractiveShell
InteractiveShell.ast_node_interactivity = "all"
from IPython.display import display, Latex
from sympy import *
import math
import numpy
import sympy
#from sympy.printing.dot import dotprint
微積分基礎:derivatives (微分), integrals (積分), limits (極限), series expansions (函數展開成冪級數).
from sympy import *
x, y, z = symbols('x y z')
init_printing(use_unicode=True)
diff(cos(x), x)
diff(exp(x**2), x)
diff 可以用兩種方式設置參數做多重微分:多次傳遞變量,或在變量後傳遞數字。
diff(x**4, x, x, x)
diff(x**4, x, 3)
diff可以一次對多個變量求導數。只需按與單個變量導數相同的語法依次傳遞每個導數即可。
expr = exp(x*y*z)
diff(expr, x, y, y, z, z, z, z)
diff(expr, x, y, 2, z, 4)
diff(expr, x, y, y, z, 4)
diff也可以作為表達式的函數調用.
expr = exp(x*y*z)
expr.diff(x, y, y, z, 4)
使用Derivative類可以創建微分表達式,語法和diff類似.
deriv = Derivative(expr, x, y, y, z, 4)
deriv
調用 doit對微分表達式進行計算.
deriv.doit()
沒有完成計算的導數表達式可以用於輸出。可以使用元組(x, n)創建未指定階數的導數,其中n是相對於x的導數階數。
m, n, a, b = symbols('m n a b')
expr = (a*x + b)**m
expr.diff((x, n))
使用integrate求兩種積分(integral),定積分(definite integral)和不定積分(indefinite integral)。SymPy不包含「積分常數C」。
使用oo表示∞.求定積分的時候,積分變量參數為 (integration_variable, lower_limit, upper_limit).
integrate(cos(x), x)
integrate(exp(-x), (x, 0, oo))
integrate(exp(-x**2 - y**2), (x, -oo, oo), (y, -oo, oo))
如果integrate計算不了,返回一個Integral對象.
expr = integrate(x**x, x)
expr
Integral(x**x, x)
expr = Integral(log(x)**2, x)
expr
expr.doit()
integrate使用了不斷改進的強大算法來計算定積分和不定積分,包括啟發式模式匹配類型算法,Risch算法的部分實現以及使用Meijer G函數的算法,該算法可用於在特殊函數方面計算積分 ,尤其是定積分。這是一些集成能力的示例。
integ = Integral((x**4 + x**2*exp(x) - x**2 - 2*x*exp(x) - 2*x -
exp(x))*exp(x)/((x - 1)**2*(x + 1)**2*(exp(x) + 1)), x)
integ
integ.doit()
integ = Integral(sin(x**2), x)
integ
integ.doit()
integ = Integral(x**y*exp(-x), (x, 0, oo))
integ
integ.doit()
This last example returned a Piecewise expression because the integral does not converge unless R(y)>1.
6.3. 極限(Limits)使用limit計算極限.如果極限趨向的點是奇異點,那麼就要使用limit替代subs進行評估。
limit(sin(x)/x, x, 0)
expr = x**2/exp(x)
expr.subs(x, oo)
limit(expr, x, oo)
和導數類 Derivative與積分類Integral一樣, limit也有一個相應的Limit類. 使用doit進行計算.注意對於極限limit,區分左極限和右極限,傳遞+或-作為第四個參數。
f = Limit((cos(x) - 1)/x, x, 0)
Eq(f,f.doit())
limit(1/x, x, 0, '+')
limit(1/x, x, 0, '-')
使用f(x).series(x, x0, n)展開f(x)在x=x0附近到xn階的漸近級數,預設是x0=0和n=6。
f = exp(sin(x))
f.series(x, 0, 4)
Eq(f,f.series(x, 0, 4))
最後的O(x4)項表示x = 0處的Landau階項,這意味著將刪除所有x的冪大於或等於x4的項。
x + x**3 + x**6 + O(x**4)
x*O(1)
採用removeO刪除最後的大O項。
expr.series(x, 0, 4).removeO()
可以設置O項的階次:
exp(x - 6).series(x, x0=6)
到目前為止,我們已經分別研究了具有解析導數(analytic derivatives)和原始函數(primitive functions)的表達式。但是,如果我們想要一個表達式來估計曲線的導數(derivative),而該表達式我們缺少閉合形式(closed form)的表示,或者尚不知道其函數值,該怎麼辦。一種方法是使用有限差分法。
使用有限差分進行區分的最簡單方法是使用differentiate_finite函數:
f, g = symbols('f g', cls=Function)
differentiate_finite(f(x)*g(x))
如果我們想擴展中間導數(intermediate derivative),我們可以使用參數evaluate=True:
differentiate_finite(f(x)*g(x), evaluate=True)
This form however does not respect the product rule.
If you already have a Derivative instance, you can use the as_finite_difference method to generate approximations of the derivative to arbitrary order:
f = Function('f')
dfdx = f(x).diff(x)
dfdx.as_finite_difference()
here the first order derivative was approximated around x using a minimum number of points (2 for 1st order derivative) evaluated equidistantly using a step-size of 1. We can use arbitrary steps (possibly containing symbolic expressions):
f = Function('f')
d2fdx2 = f(x).diff(x, 2)
h = Symbol('h')
d2fdx2.as_finite_difference([-3*h,-h,2*h])
If you are just interested in evaluating the weights, you can do so manually:
finite_diff_weights(2, [-3, -1, 2], 0)[-1][-1]
note that we only need the last element in the last sublist returned from finite_diff_weights. The reason for this is that the function also generates weights for lower derivatives and using fewer points (see the documentation of finite_diff_weights for more details).
If using finite_diff_weights directly looks complicated, and the as_finite_difference method of Derivative instances is not flexible enough, you can use apply_finite_diff which takes order, x_list, y_list and x0 as parameters:
x_list = [-3, 1, 2]
y_list = symbols('a b c')
apply_finite_diff(1, x_list, y_list, 0)
from sympy import *
x, y, z = symbols('x y z')
init_printing(use_unicode=True)
SymPy的符號等式(symbolic equations)不是用= 或 ==, 而是用 Eq.
Eq(x, y)
在solve函數中,一個沒有使用Eq的表達式默認等於0. 由於a=b和a-b=0等價,所以x == y可以直接表示為x - y.
solveset(Eq(x**2, 1), x)
solveset(Eq(x**2 - 1, 0), x)
solveset(x**2 - 1, x)
求解代數方程(algebraic equations)的函數: solveset(equation, variable=None, domain=S.Complexes).
solve也可以用於求解方程:solve(equations, variables). 但是推薦使用solveset.
當求解一個方程時,solveset的輸出是:FiniteSet,Interval 或 ImageSet.
solveset(x**2 - x, x)
solveset(x - x, x, domain=S.Reals)
solveset(sin(x) - 1, x, domain=S.Reals)
如果無解,返回EmptySet;如果解不出來,返回ConditionSet.
solveset(exp(x), x) # No solution exists
solveset(cos(x) - x, x) # Not able to find solution
在solveset模塊中,線性方程組求解使用linsolve.
以方程列表作為輸入:
from sympy import *
x, y, z = symbols('x y z')
linsolve([x + y + z - 1, x + y + 2*z - 3 ], (x, y, z))
增強矩陣形式:
linsolve(Matrix(([1, 1, 1, 1], [1, 1, 2, 3])), (x, y, z))
A*x = b Form
M = Matrix(((1, 1, 1, 1), (1, 1, 2, 3)))
system = A, b = M[:, :-1], M[:, -1]
linsolve(system, x, y, z)
linsolve((A, b),(x,y,z))
在solveset模塊中,非線性系統(non linear system)通過nonlinsolve求解.
通過生成符號時指定real=True則僅求解實數解:
a, b, c, d = symbols('a, b, c, d', real=True)
nonlinsolve([a**2 + a, a - b], [a, b])
nonlinsolve([x*y - 1, x - 2], x, y)
否則將返回複數(complex)解:
nonlinsolve([x**2 + 1, y**2 + 1], [x, y])
下面時返回實數和複數的例子:
from sympy import sqrt
system = [x**2 - 2*y**2 -2, x*y - 2]
vars = [x, y]
nonlinsolve(system, vars)
system = [exp(x) - sin(y), 1/y - 3]
nonlinsolve(system, vars)
當系統是正維(positive-dimensional)系統時(具有無限多個解):
nonlinsolve([x*y, x*y - x], [x, y])
system = [a**2 + a*c, a - b]
nonlinsolve(system, [a, b])
Currently nonlinsolve doesn’t return solution in form of LambertW (if there is solution present in the form of LambertW).
solve can be used for such cases:
solve([x**2 - y**2/exp(x)], [x, y], dict=True)
Currently nonlinsolve is not properly capable of solving the system of equations having trigonometric functions.
solve can be used for such cases (but does not give all solution):
solve([sin(x + y), cos(x - y)], [x, y])
solveset對於一個解之返回1次;使用roots獲得包含多重值的多項式的解.
solveset(x**3 - 6*x**2 + 9*x, x)
roots(x**3 - 6*x**2 + 9*x, x)
輸出{0: 1, 3: 2}表示0出現1次,3出現2次.
注意: solveset不能求解:LambertW (Transcendental equation solver).
solve能夠求解並返回如下:
solve(x*exp(x) - 1, x )
使用dsolve解微分方程。通過將cls=Function傳遞給symbols函數來創建一個未定義的函數。
f, g = symbols('f g', cls=Function)
f(x)
f 和 g 尚未定義。調用f(x)時它表示一個未知函數.則f(x)的導數不能計算.
f(x).diff(x)
diffeq = Eq(f(x).diff(x, x) - 2*f(x).diff(x) + f(x), sin(x))
diffeq
求解常微分方程(ODE), 將之作為參數傳遞給dsolve.
dsolve(diffeq, f(x))
dsolve returns an instance of Eq. This is because in general, solutions to differential equations cannot be solved explicitly for the function.
dsolve(f(x).diff(x)*(1 - sin(f(x))) - 1, f(x))
The arbitrary constants in the solutions from dsolve are symbols of the form C1, C2, C3, and so on.
8. Matricesfrom sympy import *
init_printing(use_unicode=True)
To make a matrix in SymPy, use the Matrix object. A matrix is constructed by providing a list of row vectors that make up the matrix. For example, to construct the matrix
Matrix([[1, -1], [3, 4], [0, 2]])
To make it easy to make column vectors, a list of elements is considered to be a column vector.
Matrix([1, 2, 3])
Matrices are manipulated just like any other object in SymPy or Python.
M = Matrix([[1, 2, 3], [3, 2, 1]])
N = Matrix([0, 1, 1])
M*N
One important thing to note about SymPy matrices is that, unlike every other object in SymPy, they are mutable. This means that they can be modified in place, as we will see below. The downside to this is that Matrix cannot be used in places that require immutability, such as inside other SymPy expressions or as keys to dictionaries. If you need an immutable version of Matrix, use ImmutableMatrix.
8.1. Basic Operations8.1.1. ShapeHere are some basic operations on Matrix. To get the shape of a matrix use shape
M = Matrix([[1, 2, 3], [-2, 0, 4]])
M
M.shape
To get an individual row or column of a matrix, use row or col. For example, M.row(0) will get the first row. M.col(-1) will get the last column.
M = Matrix([[1, 2, 3], [-2, 0, 4]])
M.row(0)
M.col(-1)
To delete a row or column, use row_del or col_del. These operations will modify the Matrix in place.
M = Matrix([[1, 2, 3], [-2, 0, 4]])
M.col_del(0)
M
M.row_del(1)
M
To insert rows or columns, use row_insert or col_insert. These operations do not operate in place.
M = Matrix([[1, 2, 3], [-2, 0, 4]])
M
M = M.row_insert(1, Matrix([[0, 4, 9]]))
M
M = M.col_insert(0, Matrix([1, -2, 6]))
M
As noted above, simple operations like addition and multiplication are done just by using +, , and *. To find the inverse of a matrix, just raise it to the -1 power.
M = Matrix([[1, 3], [-2, 3]])
N = Matrix([[0, 3], [0, 7]])
M + N
M*N
3*M
M**2
M**-1
Matrix det == 0, not invertible, raise NonInvertibleMatrixError.
N = Matrix([[0, 3], [0, 7]])
try:
N**-1
except:
N.T
To take the transpose of a Matrix, use T.
M = Matrix([[1, 2, 3], [4, 5, 6]])
M
M.T
Several constructors exist for creating common matrices.
To create an identity matrix, use eye. eye(n) will create an n×n identity matrix.
To create a matrix of all zeros, use zeros. zeros(n, m) creates an n×m matrix of 0s.
Similarly, ones creates a matrix of ones.
To create diagonal matrices, use diag. The arguments to diag can be either numbers or matrices. A number is interpreted as a 1×1 matrix. The matrices are stacked diagonally. The remaining elements are filled with 0s.
eye(3)
eye(4)
zeros(2, 3)
ones(3, 2)
diag(1, 2, 3)
diag(-1, ones(2, 2), Matrix([5, 7, 5]))
To compute the determinant of a matrix, use det.
M = Matrix([[1, 0, 1], [2, -1, 3], [4, 3, 2]])
M
M.det()
To put a matrix into reduced row-echelon form (簡化行梯形形式), use rref. rref returns a tuple of two elements. The first is the reduced row echelon form, and the second is a tuple of indices of the pivot columns.
Note: The first element of the tuple returned by rref is of type Matrix. The second is of type tuple.
M = Matrix([[1, 0, 1, 3], [2, 3, 4, 7], [-1, -3, -3, -4]])
M
M.rref()
To find the nullspace of a matrix, use nullspace. nullspace returns a list of column vectors that span the nullspace of the matrix.
M = Matrix([[1, 2, 3, 0, 0], [4, 10, 0, 0, 1]])
M
M.nullspace()
columnspace returns a list of column vectors that span the column space of the matrix.
M = Matrix([[1, 1, 2], [2 ,1 , 3], [3 , 1, 4]])
M
M.columnspace()
eigenvals returns a dictionary of eigenvalue: algebraic multiplicity pairs (similar to the output of roots).
M = Matrix([[3, -2, 4, -2], [5, 3, -3, -2], [5, -2, 2, -2], [5, -2, -3, 3]])
M
M.eigenvals()
This means that M has eigenvalues -2, 3, and 5, and that the eigenvalues -2 and 3 have algebraic multiplicity 1 and that the eigenvalue 5 has algebraic multiplicity 2.
eigenvects returns a list of tuples of the form (eigenvalue:algebraic multiplicity, [eigenvectors]).
M.eigenvects()
This shows us that, for example, the eigenvalue 5 also has geometric multiplicity 2, because it has two eigenvectors. Because the algebraic and geometric multiplicities are the same for all the eigenvalues, M is diagonalizable.
This shows us that, for example, the eigenvalue 5 also has geometric multiplicity 2, because it has two eigenvectors. Because the algebraic and geometric multiplicities are the same for all the eigenvalues, M is diagonalizable.
To diagonalize a matrix, use diagonalize. diagonalize returns a tuple (P,D), where D is diagonal and M=PDP^-1.
P, D = M.diagonalize()
P
D
P*D*P**-1
P*D*P**-1 == M
Note: that since eigenvects also includes the eigenvalues, you should use it instead of eigenvals if you also want the eigenvectors. However, as computing the eigenvectors may often be costly, eigenvals should be preferred if you only wish to find the eigenvalues.
Quick Tip: lambda is a reserved keyword in Python, so to create a Symbol called λ, while using the same names for SymPy Symbols and Python variables, use lamda (without the b). It will still pretty print as λ.
If all you want is the characteristic polynomial, use charpoly (特徵方程求解原式). This is more efficient than eigenvals, because sometimes symbolic roots can be expensive to calculate.
lamda = symbols('lamda')
p = M.charpoly(lamda)
factor(p)
If your matrix operations are failing or returning wrong answers, the common reasons would likely be from zero testing. If there is an expression not properly zero-tested, it can possibly bring issues in finding pivots for gaussian elimination, or deciding whether the matrix is inversible, or any high level functions which relies on the prior procedures.
Currently, the SymPy’s default method of zero testing _is zero is only guaranteed to be accurate in some limited domain of numerics and symbols, and any complicated expressions beyond its decidability are treated as None, which behaves similarly to logical False.
The list of methods using zero testing procedures are as follows:
echelon_form , is_echelon , rank , rref , nullspace , eigenvects , inverse_ADJ , inverse_GE , inverse_LU , LUdecomposition , LUdecomposition_Simple , LUsolve
They have property iszerofunc opened up for the user to specify zero testing method, which can accept any function with a single input and boolean output while being defaulted with _iszero.
Here is an example of solving an issue caused by undertested zero.
from sympy import *
q = Symbol("q", positive = True)
m = Matrix([
[-2*cosh(q/3), exp(-q), 1],
[ exp(q), -2*cosh(q/3), 1],
[ 1, 1, -2*cosh(q/3)]])
m.nullspace()
You can trace down which expression is being underevaluated, by injecting a custom zero test with warnings enabled.
import warnings
def my_iszero(x):
try:
result = x.is_zero
except AttributeError:
result = None
# Warnings if evaluated into None
if result is None:
warnings.warn("Zero testing of {} evaluated into None".format(x))
return result
m.nullspace(iszerofunc=my_iszero)
In this case, (-exp(q) - 2cosh(q/3))(-2cosh(q/3) - exp(-q)) - (4cosh(q/3)2 - 1)2 should yield zero, but the zero testing had failed to catch. possibly meaning that a stronger zero test should be introduced. For this specific example, rewriting to exponentials and applying to simplify would make zero tests stronger for hyperbolics, while being harmless to other polynomials or transcendental functions.
def my_iszero(x):
try:
result = x.rewrite(exp).simplify().is_zero
except AttributeError:
result = None
# Warnings if evaluated into None
if result is None:
warnings.warn("Zero testing of {} evaluated into None".format(x))
return result
m.nullspace(iszerofunc=my_iszero)
You can clearly see nullspace returning proper result, after injecting an alternative zero test.
Note that this approach is only valid for some limited cases of matrices containing only numerics, hyperbolics, and exponentials. For other matrices, you should use different method opted for their domains.
Possible suggestions would be either taking advantage of rewriting and simplifying, with tradeoff of speed 3 , or using random numeric testing, with tradeoff of accuracy 4 .
If you wonder why there is no generic algorithm for zero testing that can work with any symbolic entities, it’s because of the constant problem stating that zero testing is undecidable 5 , and not only the SymPy, but also other computer algebra systems 6 7 would face the same fundamental issue.
However, discovery of any zero test failings can provide some good examples to improve SymPy, so if you have encountered one, you can report the issue to SymPy issue tracker 8 to get detailed help from the community.
8.6. FootnotesInspired by https://gitter.im/sympy/sympy?at=5b7c3e8ee5b40332abdb206c
Discovered from https://github.com/sympy/sympy/issues/15141
Suggested from https://github.com/sympy/sympy/issues/10120
Suggested from https://github.com/sympy/sympy/issues/10279
https://en.wikipedia.org/wiki/Constant_problem
How mathematica tests zero https://reference.wolfram.com/language/ref/PossibleZeroQ.html
How matlab tests zero https://www.mathworks.com/help/symbolic/mupad_ref/iszero.html
https://github.com/sympy/sympy/issues
定量分析方法第01講:課程概況
定量分析方法第02講:Python基礎
定量分析方法第03講:Numpy基礎
定量分析方法第04講:Scipy基礎
定量分析方法第05講:表格數據分析
定量分析方法第06講:Pandas表格
定量分析方法第07講:Pandas速查表
定量分析方法第08講:Pandas可視化
定量分析方法第09講:矩陣分析基礎一
定量分析方法第10講:矩陣分析基礎二
定量分析方法第11講:矩陣分析算例1-3
定量分析方法第12講:矩陣分析算例4-6
定量分析方法第13講:數學分析的概念
定量分析方法第14講:Sympy數學分析基礎I
優化問題、模型與算法
旅行商問題(Traveling Salesman Problem)求解算法
[公開課] 物流系統優化與決策: 旅行商問題
[公開課] 物流系統優化與決策: 旅行商問題
[公開課] 物流系統優化與決策: 無容量約束倉庫選址
[公開課] 物流系統優化與決策: 容量約束倉庫選址
[公開課] 物流系統優化與決策: 無容量約束p-median選址
[公開課] 物流系統優化與決策: 容量約束p-median選址
[公開課] 物流系統優化與決策: 多源Weber選址
[公開課] 物流系統優化與決策: p-hub選址
機器學習
機器學習: 鳶尾花數據集
機器學習: Scikit-learn Getting Started
機器學習: An introduction to machine learning with scikit-learn
機器學習: 手寫數字識別
機器學習: 人臉補全
Python普通最小二乘法
[公開課]機器學習(01-04): 四個例子
[公開課]機器學習(05-06): 分類結果的評價
[公開課]機器學習(07): 從Scikit-learn看機器學習
[公開課]機器學習(08): 機器學習概念解讀
[公開課]機器學習(09):統計學習及監督學習概論
[公開課]機器學習(10): 感知機
[公開課]機器學習(11):k近鄰法
[公開課]機器學習(12):樸素貝葉斯法
[公開課]機器學習(13):樸素貝葉斯法重述、第10-12講的Python算法
[公開課]機器學習(14):梯度下降法
[公開課]機器學習(15):拉格朗日對偶
[公開課]機器學習(16):決策樹
[公開課]機器學習(17): 邏輯斯特回歸
[公開課]機器學習(18): 最大熵模型
[公開課]機器學習(19): 線性可分支持向量機
[公開課]機器學習(20): 線性支持向量機
[公開課]機器學習(21): 非線性支持向量機
[公開課]機器學習(22): 支持向量機實驗
[公開課]機器學習(23): 提升方法Adaboost
[公開課]機器學習(24): 隱馬爾科夫模型
[公開課]機器學習(25): 聚類方法
[公開課]機器學習(26): 主成分分析
[公開課]機器學習(27): 神經網絡
[公開課]機器學習(28): 集成學習
機器學習28講視頻合集
[公開課]機器學習28講視頻合集01-10
[公開課]機器學習28講視頻合集11-20
[公開課]機器學習28講視頻合集21-28
ALNS自適應大規模鄰域搜索
ALNS自適應大規模鄰域搜索: 套裁問題
ALNS自適應大規模鄰域搜索: 旅行商問題
SCIP數學規劃
SCIP數學規劃求解器: PySCIPOpt
SCIP: 奇數還是偶數
SCIP: 邏輯約束
SCIP: 四個ATSP模型
SCIP: 1D裝箱問題的算法與模型
SCIP: 多商品經濟批量訂貨模型(MEOQ)線性化
SCIP: 選址問題(k-median)
SCIP: 容量約束下多分配選址問題
SCIP: 圖著色問題(限定色數)
SCIP: 批量(lot-sizing)優化問題與割平面
SCIP: 最大穩定集問題
SCIP: permutation flow shop
SCIP: 多商品經濟批量訂貨模型(MEOQ)線性化
SCIP: 資源約束調度問題RCSP
SCIP: 魯棒生產模型(SOCP)
SCIP 05: 整數規劃例子
SCIP: 圖著色的三個模型
SCIP: Weber問題的二階錐模型
SCIP: 設施選址問題的分解模型
SCIP: 數獨(sudoku)整數規劃模型
SCIP: 割平面求解TSP的算法
Python進化計算
Python進化計算Geatpy要點
單目標單連續變量函數二進位編碼進化算法
單目標多連續變量帶約束實數編碼進化算法
帶約束的單目標旅行商問題進化算法
句子匹配單目標進化算法
混合編碼單目標進化算法
離散變量雙目標進化算法
連續變量雙目標進化算法
多目標背包進化算法
混合編碼多目標背包進化算法
Python優化
Python無約束非線性優化
Python差分進化算法
Python線性規劃
Python 數學規劃
Python數學規劃案例:單分配多樞紐站選址
Python數學規劃案例:單源設施選址
Python數學規劃案例:路徑優化CVRP
Python數學規劃案例:一維裝箱
Python數學規劃案例四:資源約束的最短路徑
Python數學規劃案例三:最短路徑
Python數學規劃案例二
Python數學規劃之Cplex之旅
Python數學規劃案例一
Python數學規劃案例一模型
Python: 數學規劃
數學規划算法十二講
單純型算法第1-4講
單純型算法第1-4講視頻
單純型算法第5-8講
單純型算法第9-10講
單純型算法第11-12講
Python數據結構
Python數據結構
Python圖
Python二叉樹
Python排序
Python查找算法
Python遞歸
Python鍊表
Python棧
Python圖(csgraph)
Python數據
Python: 資料庫之SQLite
Python: Pandas
Python資料庫
Numpy快速入門
Pandas入門
Python Web
幾分鐘做個Web應用
Python信息系統實驗:倉庫管理
Python基礎
Python基礎:沒有更簡單
Python利器
Python快速入門
Python 入門
程序設計
如何學習程序設計
Python技術複雜性