
本文介绍如何使用 SymPy 对形如 $ V = f(r)\,x^2 $(其中 $ r = \sqrt{x^2+y^2+z^2} $,$ f $ 为未指定的具体函数)的符号表达式关于 $ x $ 求导,并避免出现 Subs 和 _xi_1 等不直观中间变量,从而获得符合数学习惯的链式法则表达式:$ \frac{x^3}{r}\,f'(r) + 2x\,f(r) $。
本文介绍如何使用 sympy 对形如 $ v = f(r)\,x^2 $(其中 $ r = \sqrt{x^2+y^2+z^2} $,$ f $ 为未指定的具体函数)的符号表达式关于 $ x $ 求导,并避免出现 `subs` 和 `_xi_1` 等不直观中间变量,从而获得符合数学习惯的链式法则表达式:$ \frac{x^3}{r}\,f'(r) + 2x\,f(r) $。
在 SymPy 中直接将 r 定义为表达式(如 sp.sqrt(x**2 + y**2 + z**2))再传入 Function('f_A')(r),会导致求导时自动展开为 Subs(Derivative(...)) 形式——这是 SymPy 为保证严格性而采用的惰性求值机制,但可读性差,不便于后续解析或 LaTeX 渲染。
更优策略是将 r 显式建模为一个符号函数 r(x, y, z),再将其作为 f_A 的自变量。这样,diff() 会自然按链式法则生成结构清晰的导数项:
import sympy as sp
x, y, z = sp.symbols('x y z')
r = sp.Function("r")(x, y, z) # r 作为抽象函数:r(x, y, z)
r_expr = sp.sqrt(x**2 + y**2 + z**2) # r 的具体表达式
f_A = sp.Function('f_A')(r) # f_A 作用于 r(x,y,z)
V = f_A * x**2
dV_dx = V.diff(x)此时 dV_dx 输出为:
x**2*Derivative(f_A(r(x, y, z)), r(x, y, z))*Derivative(r(x, y, z), x) + 2*x*f_A(r(x, y, z))
该结果明确分离出两部分:
- $ \displaystyle \frac{df_A}{dr} \cdot \frac{\partial r}{\partial x} $(链式法则核心)
- $ 2x\,f_A(r) $(乘积法则中对 $ x^2 $ 的求导)
接下来,用 subs() 将抽象导数 Derivative(r(x,y,z), x) 替换为其显式值:
dV_dx_simplified = dV_dx.subs(sp.Derivative(r, x), r_expr.diff(x)) print(sp.simplify(dV_dx_simplified))
输出即为:
x**3*Derivative(f_A(r(x, y, z)), r(x, y, z))/sqrt(x**2 + y**2 + z**2) + 2*x*f_A(r(x, y, z))
若希望进一步将 Derivative(f_A(r(x,y,z)), r(x,y,z)) 显示为更简洁的 $ f_A'(r) $,可借助 sp.Derivative 的 .doit() 配合自定义替换,或直接使用 sp.symbols("f_prime") 进行语义标注;但在纯符号推导中,保留 Derivative(f_A(r), r) 已是最规范、可微分且可继续参与高阶运算的形式。
✅ 关键要点总结:
- ❌ 避免
f_A(sp.sqrt(...))直接嵌套 —— 导致Subs和_xi_1干扰可读性; - ✅ 使用
sp.Function("r")(x,y,z)抽象建模中间变量,使链式法则显式化; - ✅ 用
.subs(Derivative(r,x), r_expr.diff(x))注入具体偏导,兼顾符号性与可解释性; - ✅ 结果天然支持 LaTeX 输出(如
sp.latex(dV_dx_simplified)),便于论文或文档集成。
此方法广泛适用于物理建模(如势函数 $ V(\mathbf{r}) $)、坐标变换下的微分推导及符号 Jacobian 构造等场景。

















