活跃弃用列表

本页面列出了 SymPy 代码库中所有活跃的弃用项。有关 SymPy 弃用政策的描述以及贡献者如何弃用内容的说明,请参阅 弃用政策 页面。

特别是,SymPy 的弃用政策规定,弃用至少在包含该弃用的第一个主要版本发布后 1年 内有效。在此期间之后,被弃用的功能可能会从 SymPy 中移除,代码需要更新以使用替代功能以继续工作。

在弃用期间,每当使用已弃用的功能时,将打印一条 SymPyDeprecationWarning 消息。建议用户更新他们的代码,使其不再使用已弃用的功能,如下文所述,针对每个弃用功能。

静默 SymPy 弃用警告

要屏蔽 SymPy 的弃用警告,请使用 warnings 模块添加一个过滤器。例如:

import warnings
from sympy.utilities.exceptions import SymPyDeprecationWarning

warnings.filterwarnings(
    # replace "ignore" with "error" to make the warning raise an exception.
    # This useful if you want to test you aren't using deprecated code.
    "ignore",

    # message may be omitted to filter all SymPyDeprecationWarnings
    message=r"(?s).*<regex matching the warning message>",

    category=SymPyDeprecationWarning,
    module=r"<regex matching your module>"
)

这里 (?s).*<匹配警告消息的正则表达式> 是一个匹配警告消息的正则表达式。例如,要过滤关于 sympy.printing 的警告,您可能会使用 message=r"(?s).*sympy\.printing"。前面的 (?s).* 是因为 warnings 模块将 message 与警告消息的开头进行匹配,并且因为典型的警告消息跨越多行。

<regex matching your module> 应该是一个匹配使用已弃用代码的模块的正则表达式。建议包含此项,以免同时屏蔽无关模块的相同警告。

这个相同的模式也可以用来将 SymPyDeprecationWarning 转换为错误,以便你可以测试你是否没有使用已弃用的代码。为此,在上面的例子中,将 "ignore" 替换为 "error"。你也可以省略 message,使这适用于所有 SymPyDeprecationWarning 警告。

如果你使用的是 pytest,你可以使用 pytest 的警告过滤功能 来忽略 SymPyDeprecationWarning 或将它们转换为错误。

备注

Python 的 -W 标志PYTHONWARNINGS 环境变量 将无法用于过滤 SymPy 的弃用警告(详情请参见 Ned Batchelder 的 这篇博客文章这个 SymPy 问题)。你需要添加如上所述的 warnings 过滤器,或者使用 pytest 来过滤 SymPy 的弃用警告。

版本 1.14

SymPy 1.14 目前没有弃用的功能。

版本 1.13

已弃用的机械体类

sympy.physics.mechanics 模块中的 Body 类已被弃用。它最初是为了支持关节框架而引入的。然而,由于它同时代表刚体和粒子,导致了一些问题。Body 现在已被 RigidBodyParticle 完全取代。以前,可以通过仅使用 Body 类来创建一个简单的刚体或粒子:

>>> from sympy import symbols
>>> from sympy.physics.mechanics import Body
>>> Body("rigid_body")  
rigid_body
>>> Body("particle", mass=symbols("m"))  
particle

现在它们应该使用 RigidBodyParticle 类来创建:

>>> from sympy.physics.mechanics import RigidBody, Particle
>>> RigidBody("rigid_body")
rigid_body
>>> Particle("particle")
particle

已弃用的机械连接 JointsMethod

sympy.physics.mechanics 模块中的 JointsMethod 类已被弃用。它最初是为了支持关节框架而引入的,但由于其设计上的局限性,已被完全取代。以前,可以仅由刚体和关节构建系统,然后由 JointsMethod 解析到后端,如 KanesMethod 以形成运动方程。

>>> from sympy import symbols
>>> from sympy.physics.mechanics import (
...   Body, JointsMethod, PinJoint, PrismaticJoint)
>>> g, l = symbols("g l")
>>> wall = Body("wall")
>>> cart = Body("cart")
>>> pendulum = Body("Pendulum")
>>> slider = PrismaticJoint("s", wall, cart, joint_axis=wall.x)
>>> pin = PinJoint("j", cart, pendulum, joint_axis=cart.z,
...                child_point=l * pendulum.y)
>>> pendulum.masscenter.set_vel(pendulum.frame, 0)
>>> cart.apply_force(-g * cart.mass * wall.y)
>>> pendulum.apply_force(-g * pendulum.mass * wall.y)
>>> method = JointsMethod(wall, slider, pin)  
>>> method.form_eoms()  
Matrix([
[ Pendulum_mass*l*u_j(t)**2*sin(q_j(t)) - Pendulum_mass*l*cos(q_j(t))*Derivative(u_j(t), t) - (Pendulum_mass + cart_mass)*Derivative(u_s(t), t)],
[-Pendulum_mass*g*l*sin(q_j(t)) - Pendulum_mass*l*cos(q_j(t))*Derivative(u_s(t), t) - (Pendulum_izz + Pendulum_mass*l**2)*Derivative(u_j(t), t)]])

JointsMethod 的替代品是 System,它可以用来形成与以下相同的推车摆杆的运动方程:

>>> from sympy import symbols
>>> from sympy.physics.mechanics import (
...   Particle, PinJoint, PrismaticJoint, RigidBody, System)
>>> g, l = symbols("g l")
>>> wall = RigidBody("wall")
>>> cart = RigidBody("cart")
>>> pendulum = RigidBody("Pendulum")
>>> slider = PrismaticJoint("s", wall, cart, joint_axis=wall.x)
>>> pin = PinJoint("j", cart, pendulum, joint_axis=cart.z,
...                child_point=l * pendulum.y)
>>> system = System.from_newtonian(wall)
>>> system.add_joints(slider, pin)
>>> system.apply_uniform_gravity(-g * wall.y)
>>> system.form_eoms()
Matrix([
[ Pendulum_mass*l*u_j(t)**2*sin(q_j(t)) - Pendulum_mass*l*cos(q_j(t))*Derivative(u_j(t), t) - (Pendulum_mass + cart_mass)*Derivative(u_s(t), t)],
[-Pendulum_mass*g*l*sin(q_j(t)) - Pendulum_mass*l*cos(q_j(t))*Derivative(u_s(t), t) - (Pendulum_izz + Pendulum_mass*l**2)*Derivative(u_j(t), t)]])

已弃用的矩阵混合类

矩阵混合类已被弃用。以前,Matrix 类(也称为 MutableDenseMatrix)是通过一个继承层次结构创建的,看起来像:

class MatrixRequired:
class MatrixShaping(MatrixRequired):
class MatrixSpecial(MatrixRequired):
class MatrixProperties(MatrixRequired):
class MatrixOperations(MatrixRequired):
class MatrixArithmetic(MatrixRequired):
class MatrixCommon(
    MatrixArithmetic,
    MatrixOperations,
    MatrixProperties,
    MatrixSpecial,
    MatrixShaping):
class MatrixDeterminant(MatrixCommon):
class MatrixReductions(MatrixDeterminant):
class MatrixSubspaces(MatrixReductions):
class MatrixEigen(MatrixSubspaces)
class MatrixCalculus(MatrixCommon):
class MatrixDeprecated(MatrixCommon):
class MatrixBase(MatrixDeprecated,
   MatrixCalculus,
   MatrixEigen,
   MatrixCommon,
   Printable):
class RepMatrix(MatrixBase):
class DenseMatrix(RepMatrix):
class MutableRepMatrix(RepMatrix):
class MutableDenseMatrix(DenseMatrix, MutableRepMatrix):

从 SymPy 1.13 开始,这已经简化,所有高于 MatrixBase 的类都被合并在一起,因此层次结构看起来像:

class MatrixBase(Printable):
class RepMatrix(MatrixBase):
class DenseMatrix(RepMatrix):
class MutableRepMatrix(RepMatrix):
class MutableDenseMatrix(DenseMatrix, MutableRepMatrix):

MatrixRequired 等矩阵混合类仍然可用,因为下游代码可能正在子类化这些类,但这些类都已弃用,并将在SymPy的未来版本中移除。子类化这些类已弃用,任何这样做的代码都应该修改为不子类化它们。

使用这些类与 isinstanceisinstance(M, MatrixCommon) 也是不推荐的。任何这样做的代码都应该改为使用 isinstance(M, Matrixbase),这样也可以兼容之前的 SymPy 版本。

更一般地说,从定义了这些类的 sympy.matrices.commonsympy.matrices.matrices 模块中导入任何内容已被弃用。这些模块将在未来的 SymPy 版本中被移除。

这一更改的原因是,复杂的继承层次结构使得在仍然提供所有这些可以被继承的类的同时,难以改进 Matrix 以满足大多数用户的需求。由于这些混合类不再作为 Matrix 的一部分使用,它们在 SymPy 中不再发挥任何作用,移除这些现在未使用的代码将简化代码库。

sympify() 中的字符串回退

sympify 函数以前会将无法识别的对象转换为字符串并重试符号化。这在 SymPy 1.6 中已被弃用,并在 SymPy 1.13 中被移除。

sympify 的行为是 sympify(expr) 尝试各种方法将 expr 转换为 SymPy 对象。以前,如果所有这些方法都失败,它会取 str(expr) 并尝试使用 parse_expr() 进行解析。这个字符串回退功能在 SymPy 1.6 中被弃用,并在 SymPy 1.13 中被移除。

这种行为有几个问题:

  • 这可能会以重大方式影响性能。例如,参见问题 #18056#15416,其中它导致了高达100倍的减速。问题在于SymPy函数自动在其参数上调用sympify。每当一个函数传递给sympify不知道如何转换为SymPy对象的东西时,例如,一个Python函数类型,它将字符串传递给parse_expr()。这比默认情况下发生的直接转换要慢得多。这种情况特别发生在库代码中使用sympify()而不是_sympify()(或等效地sympify(strict=True))时,但目前这种情况很常见。使用strict=True将在某个时候成为所有库代码的默认设置,但这是一个更难的改变

  • 由于字符串会被求值,对象可以在其 __repr__ 中返回任何字符串,这可能会导致安全问题。另见 https://github.com/sympy/sympy/pull/12524。

  • 一开始它确实不是很有用。仅仅因为一个对象的字符串形式可以被解析为一个 SymPy 表达式,并不意味着它应该被那样解析。对于自定义数值类型来说,这通常是正确的,但一个对象的 repr 可以是任何东西。例如,如果一个对象的字符串形式看起来像一个有效的 Python 标识符,它将被解析为一个 Symbol

sympify() 内部有许多方法可以使自定义对象工作。

  • 首先,如果一个对象旨在与其他 SymPy 表达式一起工作,它应该从 Basic(或 Expr)子类化。如果是这样,sympify() 将直接返回它而不做改变,因为它已经是一个有效的 SymPy 对象。

  • 对于你控制的对象,你可以添加 _sympy_ 方法。sympify 文档字符串 中有一个这方面的示例。

  • 对于你不控制的物体,你可以向 sympy.core.sympify.converter 字典添加一个自定义转换器。sympify() 文档字符串中也有一个这样的例子。

弃用 DMP.rep 属性。

Poly 的内部类型是 DMP 类,以前可以像列表一样访问多项式的系数,例如:

>>> from sympy import symbols, Poly
>>> x = symbols('x')
>>> p = Poly(x**2 + 2*x + 3)
>>> p
Poly(x**2 + 2*x + 3, x, domain='ZZ')
>>> p.rep  
DMP([1, 2, 3], ZZ)
>>> p.rep.rep  
[1, 2, 3]

从 SymPy 1.13 开始,DMP 类型可能由两个子类之一实现:

  • DMP_Python 类似于之前的 DMP 类型,并且其内部表示为一个列表。

  • DUP_Flint 包装了来自 python-flint 的 Flint 多项式。

DUP_Flint 类型没有类似于 DMP_Python 的列表属性。访问 .rep 仍将生成一个列表,但现在会给出弃用警告。

使用 DMP.to_list() 方法代替 .rep,该方法返回一个等效的列表:

>>> p.rep.to_list()
[1, 2, 3]

.to_list() 方法在 SymPy 的早期版本中也可用,其行为保持不变。

弃用 pkgdata 模块

sympy.utilities.pkdata 模块已被弃用,并将在未来被移除。它不再在 SymPy 的任何地方使用,也不适合任何下游代码使用。请改用标准库 importlib.resources 模块。

弃用 Eq.rewrite(Add)

eq = Eq(x, y) 重写为 eq.rewrite(Add) 以得到 x - y 的功能已被弃用,取而代之的是使用 eq.lhs - eq.rhs。鉴于 lhsrhs 的显式使用带来的清晰性,以及这种功能在重写机制中的包含会导致在将期望布尔值的节点重写为 Expr 时失败,因此没有必要提供替代的属性/方法。

弃用 Plot 类的标记、注释、填充、矩形

属性 markers, annotations, fill, rectangles(包含用户提供的要添加到图表中的数值数据)已被弃用。新的实现将用户提供的数值数据保存到适当的数据系列中,这些数据系列可以很容易地由 MatplotlibBackend 处理。用户应将同名关键字参数传递给绘图函数,而不是直接设置这些属性。

支持的行为是将关键字参数传递给绘图函数,这对于所有版本的 SymPy(1.13 之前和之后)都适用:

p = plot(x,
  markers=[{"args":[[0, 1], [0, 1]], "marker": "*", "linestyle": "none"}],
  annotations=[{"text": "test", "xy": (0, 0)}],
  fill={"x": [0, 1, 2, 3], "y1": [0, 1, 2, 3]},
  rectangles=[{"xy": (0, 0), "width": 5, "height": 1}])

在绘图对象上设置属性已被弃用,并将引发警告:

p = plot(x, show=False)
p.markers = [{"args":[[0, 1], [0, 1]], "marker": "*", "linestyle": "none"}]
p.annotations = [{"text": "test", "xy": (0, 0)}]
p.fill = {"x": [0, 1, 2, 3], "y1": [0, 1, 2, 3]}
p.rectangles = [{"xy": (0, 0), "width": 5, "height": 1}]
p.show()

此次弃用的动机:Plot 类的实现表明,在 MatplotlibBackend 类中添加属性和硬编码的 if 语句以为用户提供的数值数据提供越来越多的功能(例如添加水平线、垂直线或条形图等)是可以的。然而,这样做实际上是在重复造轮子:绘图库已经实现了必要的 API。没有必要硬编码这些功能。绘图模块应该促进符号表达式的可视化。添加自定义数值数据的最佳方式是获取绘图模块创建的图形,并使用特定绘图库的 API。例如:

# plot symbolic expression
p = plot(cos(x))
# retrieve Matplotlib's figure and axes object
fig, ax = p._backend.fig, p._backend.ax[0]
# add the desired numerical data using Matplotlib's API
ax.plot([0, 1, 2], [0, 1, -1], "*")
ax.axhline(0.5)
# visualize the figure
fig

移动机械函数

随着 sympy.physics.mechanics 模块中引入了一些新对象,如 Inertia 和负载对象,sympy.physics.mechanics.functions 模块中的一些函数已被移动到新的模块中。这消除了一些循环导入错误,并使得浏览源代码变得更加容易,因为函数名与模块名之间保持了一致性。以下函数已被移动:

  • inertia 已被移动到 sympy.physics.mechanics.inertia

  • inertia_of_point_mass 已被移动到 sympy.physics.mechanics.inertia

  • gravity 已被移动到 sympy.physics.mechanics.loads

之前你可以从 sympy.physics.mechanics.functions 导入函数:

>>> from sympy.physics.mechanics.functions import inertia, inertia_of_point_mass, gravity

现在它们应该从 sympy.physics.mechanics 导入:

>>> from sympy.physics.mechanics import inertia, inertia_of_point_mass
>>> from sympy.physics.mechanics.loads import gravity

a < b 这样的有序比较与模整数

SymPy 的 GF 域表示模整数。以前可以使用 a < b 这样的有序比较来比较这些整数:

>>> from sympy import GF
>>> F5 = GF(5)
>>> F5(2) < F5(3) 
True

当基础类型设置为 flint 时,这将导致 TypeError 错误。当基础类型不是 flint 时,这些比较操作现在已被弃用:它们仍然可以使用,但在使用时会给出弃用警告。

模整数或有限域的有序比较没有意义,因为这些不是有序域:

>>> e = F5(4)
>>> e + 1 > e 
False

ModularInteger.to_int() 方法

SymPy 的 GF 域用于模整数,例如 GF(n) 用于模 n 的整数,并且可以像这样使用:

>>> from sympy import GF
>>> K = GF(5)
>>> a = K(7)
>>> a
2 mod 5

模块化整数域的元素有一个自 SymPy 1.13 起被弃用的 to_int() 方法:

>>> # this is deprecated:
>>> a.to_int()  
2

相反,实现等效行为的推荐方法是使用域上的方法(在 SymPy 1.13 中添加),或者调用 int 可能更好:

>>> K.to_int(a)
2
>>> int(a)
2

这两种转换为 int 的方法并不等价。域 GF(p) 可以用 symmetric=Truesymmetric=False 来定义。这种差异会影响 to_int 方法的行为:

>>> KS = GF(5, symmetric=True)
>>> KU = GF(5, symmetric=False)
>>> [KS.to_int(KS(n)) for n in range(10)]
[0, 1, 2, -2, -1, 0, 1, 2, -2, -1]
>>> [KU.to_int(KU(n)) for n in range(10)]
[0, 1, 2, 3, 4, 0, 1, 2, 3, 4]
>>> [int(KS(n)) for n in range(10)]
[0, 1, 2, 3, 4, 0, 1, 2, 3, 4]
>>> [int(KU(n)) for n in range(10)]
[0, 1, 2, 3, 4, 0, 1, 2, 3, 4]

因此,如果 symmetric=True(这是默认设置),那么 to_int 方法有时会返回负整数。如果 symmetric=False 或者使用 int(a) 方法,返回的结果总是一个非负整数。还要注意,int(a) 的行为在 SymPy 1.13 中发生了变化:在之前的版本中,它等同于 a.to_int()。为了编写在所有 SymPy 版本中行为一致的代码,你可以:

  1. 使用 symmetric=False 并使用 int(a)

  2. 定义一个函数,例如

    def to_int(K, a):
        if hasattr(K, 'to_int'):
            return K.to_int(a)
        else:
            return a.to_int()
    

这一更改的原因是,它使得可以使用 python-flint 的 nmod 作为 GF(p) 元素的替代(快得多)实现。无法向 python-flint 的 nmod 类型添加 to_int 方法,也无法通过在 nmod 实例中存储数据来捕获 symmetric=True/False 的等效内容。弃用并移除 to_int 方法并更改 int 方法的行为意味着元素实例没有任何行为取决于域是否被认为是“对称”的。相反,“对称”的概念现在纯粹是域对象本身的属性,而不是元素的属性,因此依赖于此的 to_int 方法必须是域方法而不是元素方法。

将符号函数从 ntheory 移动到 functions

以下 ntheory 中的符号函数已移至 functions 中:

  • sympy.ntheory.factor_.divisor_sigma

  • sympy.ntheory.factor_.primenu

  • sympy.ntheory.factor_.primeomega

  • sympy.ntheory.factor_.reduce_totient

  • sympy.ntheory.factor_.totient

  • sympy.ntheory.generate.primepi

  • sympy.partitions_.npartitions

  • sympy.ntheory.residue_ntheory.jacobi_symbol

  • sympy.ntheory.residue_ntheory.legendre_symbol

  • sympy.ntheory.residue_ntheory.mobius

从顶层导入这些函数的代码,例如 from sympy import mobius ,将继续正常工作。然而,从完全限定模块导入这些函数的代码,例如 from sympy.ntheory import mobiusfrom sympy.ntheory.residue_ntheory import mobius ,现在将会看到一个弃用警告。这些函数的新位置在 sympy.functions 中,但导入它们的预期方式仍然是像 from sympy import mobius 这样从顶层导入。

以下 ntheory 中的符号函数已移至 functions,但不能在顶层导入。

  • sympy.ntheory.factor_.udivisor_sigma

以下函数已从 functions 移动到 ntheory ,因为它们是数值函数。

  • sympy.functions.combinatorial.numbers.carmichael.is_carmichael

  • sympy.functions.combinatorial.numbers.carmichael.find_carmichael_numbers_in_range

  • sympy.functions.combinatorial.numbers.carmichael.find_first_n_carmichaels

如果你正在使用这些功能,请进行更改:

>>> from sympy import carmichael
>>> carmichael.is_carmichael(561)
True

>>> from sympy import is_carmichael
>>> is_carmichael(561)
True

版本 1.12

ManagedProperties 元类

ManagedProperties 元类以前是 Basic 的元类。现在 Basic 不使用元类,因此它的元类只是 type。任何以前继承 Basic 并希望使用元类的代码都需要继承 ManagedProperties 以使用相关的元类。ManagedProperties 的唯一相关方法已被移动到 Basic.__init_subclass__。由于 ManagedProperties 不再用作 Basic 的元类,并且不再执行任何有用操作,因此对于此类代码,可以直接继承 type 作为任何元类。

新的关节坐标格式

sympy.physics.mechanics 模块中关节的广义坐标和广义速度的格式(即类型和自动生成的名称)已更改。数据类型已从 list 更改为 Matrix,这与 KanesMethod 中广义坐标的类型相同。PinJointPrismaticJoint 的广义坐标和广义速度的自动命名也已更改为 q_<joint.name>u_<joint.name>。以前,这些关节中的每一个都有独特的模板来自动生成这些名称。

新的关节中间帧

sympy.physics.mechanics 模块中关节轴的定义已经改变。不再使用 parent_axischild_axis 参数来自动确定关节轴和中间参考系,现在关节使用中间帧参数来表示父体和子体,即 parent_interframechild_interframe。这意味着你现在可以完全定义两个物体之间的关节连接,包括点和框架。此外,如果像 PinJoint 这样的关节有特定的关节轴,例如旋转发生的轴,那么可以使用 joint_axis 参数来指定该轴。这种设置的一个优点是可以更准确地定义从父体到子体的变换。

例如,假设你想要一个围绕 parent.z 轴和 -child.z 轴旋转子体的 PinJoint。之前指定这种关节的方式是:

>>> from sympy.physics.mechanics import Body, PinJoint
>>> parent, child = Body('parent'), Body('child')
>>> pin = PinJoint('pin', parent, child, parent_axis=parent.z,
...                child_axis=-child.z)   
>>> parent.dcm(child)   
Matrix([
[-cos(q_pin(t)), -sin(q_pin(t)),  0],
[-sin(q_pin(t)),  cos(q_pin(t)),  0],
[             0,              0, -1]])

检查此矩阵时,您会注意到当 theta_pin = 0 时,子体绕 parent.y 轴旋转了 \(\pi\) 弧度。在新定义中,您可以看到我们得到了相同的结果,但这次我们还明确指定了这一旋转:

>>> from sympy import pi
>>> from sympy.physics.mechanics import Body, PinJoint, ReferenceFrame
>>> parent, child, = Body('parent'), Body('child')
>>> int_frame = ReferenceFrame('int_frame')
>>> int_frame.orient_axis(child.frame, child.y, pi)
>>> pin = PinJoint('pin', parent, child, joint_axis=parent.z,
...                child_interframe=int_frame)
>>> parent.dcm(child)
Matrix([
[-cos(q_pin(t)), -sin(q_pin(t)),  0],
[-sin(q_pin(t)),  cos(q_pin(t)),  0],
[             0,              0, -1]])

然而,如果你喜欢被弃用的参数为你对齐框架的事实,那么你仍然可以通过提供向量给 parent_interframechild_interframe 来利用这个特性,这些向量随后会被定向,使得中间框架中表达的关节轴与给定的向量对齐:

>>> from sympy.physics.mechanics import Body, PinJoint
>>> parent, child = Body('parent'), Body('child')
>>> pin = PinJoint('pin', parent, child, parent_interframe=parent.z,
...                child_interframe=-child.z)
>>> parent.dcm(child)
Matrix([
[-cos(q_pin(t)), -sin(q_pin(t)),  0],
[-sin(q_pin(t)),  cos(q_pin(t)),  0],
[             0,              0, -1]])

关节附着点参数的变化

sympy.physics.mechanics 中指定关节附着点的参数名称,即 parent_joint_poschild_joint_pos,已更改为 parent_pointchild_point。这是因为这些参数现在也可以是 Point 对象,因此它们可以与 parent_pointchild_point 属性完全相同。

例如,假设你想在父对象中将 PinJoint 定位在相对于质心的 parent.frame.x 处,而在子对象中定位在 -child.frame.x 处。以前指定这种方式是:

>>> from sympy.physics.mechanics import Body, PinJoint
>>> parent, child = Body('parent'), Body('child')
>>> pin = PinJoint('pin', parent, child, parent_joint_pos=parent.frame.x,
...                child_joint_pos=-child.frame.x)   
>>> pin.parent_point.pos_from(parent.masscenter)   
parent_frame.x
>>> pin.child_point.pos_from(child.masscenter)   
- child_frame.x

现在你可以用同样的方式进行操作。

>>> from sympy.physics.mechanics import Body, PinJoint
>>> parent, child = Body('parent'), Body('child')
>>> pin = PinJoint('pin', parent, child, parent_point=parent.frame.x,
...                child_point=-child.frame.x)
>>> pin.parent_point.pos_from(parent.masscenter)
parent_frame.x
>>> pin.child_point.pos_from(child.masscenter)
- child_frame.x

>>> from sympy.physics.mechanics import Body, PinJoint, Point
>>> parent, child = Body('parent'), Body('child')
>>> parent_point = parent.masscenter.locatenew('parent_point', parent.frame.x)
>>> child_point = child.masscenter.locatenew('child_point', -child.frame.x)
>>> pin = PinJoint('pin', parent, child, parent_point=parent_point,
...                child_point=child_point)
>>> pin.parent_point.pos_from(parent.masscenter)
parent_frame.x
>>> pin.child_point.pos_from(child.masscenter)
- child_frame.x

版本 1.11

模块 sympy.tensor.array.expressions.conv_* 已重命名为 sympy.tensor.array.expressions.from_*

为了避免与名称相似的模块名称可能导致的命名和制表符补全冲突,sympy.tensor.array.expressions 中所有名称以 conv_* 开头的模块已重命名为 from_*

新的 Mathematica 代码解析器

模块 sympy.parsing.mathematica 中定义的旧 mathematica 代码解析器 mathematica 已被弃用。应改用具有新且更全面解析器功能的 parse_mathematica 函数。

Mathematica 解析器的 additional_translations 参数在 parse_mathematica 中不可用。将 Mathematica 表达式转换为 SymPy 表达式的额外翻译规则应在转换后使用 SymPy 的 .replace( ).subs( ) 方法在输出表达式上指定。如果翻译器无法识别 Mathematica 表达式的逻辑意义,将返回类似于 Mathematica 完整形式的表达式,使用 SymPy 的 Function 对象来编码语法树的节点。

例如,假设你想让 F 成为一个函数,该函数返回最大值乘以最小值,之前指定这种转换的方式是:

>>> from sympy.parsing.mathematica import mathematica
>>> mathematica('F[7,5,3]', {'F[*x]': 'Max(*x)*Min(*x)'})   
21

现在你可以用同样的方式来

>>> from sympy.parsing.mathematica import parse_mathematica
>>> from sympy import Function, Max, Min
>>> parse_mathematica("F[7,5,3]").replace(Function("F"), lambda *x: Max(*x)*Min(*x))
21

carmichael 中的冗余静态方法

~.carmichael 中的许多静态方法只是其他函数的包装器。不要使用 carmichael.is_perfect_square,而是使用 sympy.ntheory.primetest.is_square,不要使用 carmichael.is_prime,而是使用 ~.isprime。最后,carmichael.divides 可以用检查来替代。

n % p == 0

HadamardProductMatAddMatMulcheck 参数

此参数可用于向 ~.HadamardProduct~.MatAdd~.MatMul 传递不正确的值,从而导致后续问题。check 参数将被移除,参数将始终被检查以确保正确性,即参数是矩阵或矩阵符号。

版本 1.10

一些遍历函数已被移动

一些遍历函数已经移动。具体来说,这些函数

  • bottom_up

  • interactive_traversal

  • postorder_traversal

  • preorder_traversal

  • 使用

已移动到不同的 SymPy 子模块。

这些函数应该从顶层的 sympy 命名空间中使用,例如

sympy.preorder_traversal

from sympy import preorder_traversal

通常,终端用户应使用顶级的 sympy 命名空间来访问其中的任何函数。如果一个名称位于顶层命名空间中,则不应依赖其特定的 SymPy 子模块,因为由于内部重构,函数可能会移动。

sympy.core.trace

跟踪对象 sympy.core.trace.Tr() 被移动到 sympy.physics.quantum.trace.Tr()。这是因为它仅在 sympy.physics.quantum 子模块中使用,因此将其放在那里比放在核心中更为合适。

sympy.core.compatibility 子模块

sympy.core.compatibility 子模块已被弃用。

这个子模块原本仅用于内部使用。既然 SymPy 不再支持 Python 2,这个模块就不再需要了,剩余的辅助函数已经被移动到 SymPy 代码库中更方便的地方。

本模块中的一些函数可以从 SymPy 的顶层命名空间中获得,即,

sympy.ordered
sympy.default_sort_key

from sympy import ordered, default_sort_key

通常,终端用户应使用顶级的 sympy 命名空间来访问其中的任何函数。如果一个名称位于顶层命名空间中,则不应依赖其特定的 SymPy 子模块,因为由于内部重构,函数可能会移动。

sympy.core.compatibility 中剩余的函数仅用于内部 SymPy 使用,不应被用户代码使用。

此外,这两个函数,ordereddefault_sort_key,也曾经在 sympy.utilities.iterables 中,但它们也已经被移走了。

版本 1.9

expr_free_symbols

各种 SymPy 对象的 expr_free_symbols 属性已被弃用。

expr_free_symbols 旨在表示诸如 MatrixElementIndexed 之类的索引对象为自由符号。这是为了让自由符号的导数能够工作。然而,现在不需要使用该方法也能实现这一点:

>>> from sympy import Indexed, MatrixSymbol, diff
>>> a = Indexed("A", 0)
>>> diff(a**2, a)
2*A[0]
>>> X = MatrixSymbol("X", 3, 3)
>>> diff(X[0, 0]**2, X[0, 0])
2*X[0, 0]

这是一个为了解决一个非常具体的问题而添加的通用属性,但它增加了一层在一般情况下不必要的抽象层。

  1. 已经具有结构“非表达”节点的对象,如果需要,允许用户专注于表达节点,例如。

    >>> from sympy import Derivative, symbols, Function
    >>> x = symbols('x')
    >>> f = Function('f')
    >>> Derivative(f(x), x).expr
    f(x)
    

    此属性的引入在请求 free_symbols 时鼓励了不精确的思考,因为它允许从对象的特定节点获取符号,而无需指定节点。

  2. 该属性被错误地添加到 AtomicExpr 中,因此数字作为 expr_free_symbols 返回:

    >>> S(2).expr_free_symbols 
    2
    
  3. 该概念的应用被错误地用于定义 Subs.expr_free_symbols:它在 expr_free_symbols 中添加了点的内容,但该点是一个 Tuple,因此实际上没有添加任何内容。

  4. 它在代码库中没有在其他地方使用,除了在区分 Subs 对象的上下文中,这表明它不是通用用途的东西,这一点也通过以下事实得到证实,

  5. 除了为引入的 Subs 对象的导数进行的测试外,没有添加具体的测试。

更多讨论请参见问题 #21494

sympy.stats.sample(numsamples=n)

numsamples 参数在 sympy.stats.sample() 中已被弃用。

numsamples 使 sample() 返回一个大小为 numsamples 的列表,例如

>>> from sympy.stats import Die, sample
>>> X = Die('X', 6)
>>> sample(X, numsamples=3) 
[3, 2, 3]

然而,用户可以通过列表推导轻松实现此功能

>>> [sample(X) for i in range(3)] 
[5, 4, 3]

此外,它与 size 参数冗余,该参数使得 sample 返回具有给定形状的 NumPy 数组。

>>> sample(X, size=(3,)) 
array([6, 6, 1])

历史上,sample 在 SymPy 1.7 中被修改,使其返回一个迭代器而不是样本值。由于返回的是迭代器,因此添加了一个 numsamples 参数来指定迭代器的长度。

然而,如在问题 #21563 中讨论的那样,这种新行为被认为令人困惑,因此被恢复了。现在,如果需要迭代器,应使用 sample_iter。因此,sample() 不再需要 numsamples 参数。

sympy.polys.solvers.RawMatrix

RawMatrix 类已被弃用。RawMatrix 类是 Matrix 的子类,它使用域元素而不是 Expr 作为矩阵的元素。这打破了 Matrix 的一个关键内部不变性,并且这种子类化限制了对 Matrix 类的改进。

SymPy 中唯一记录了 RawMatrix 类使用的是 Smith 标准形式代码,但现在已改为使用 DomainMatrix。建议任何使用 RawMatrix 与之前的 Smith 标准形式代码的人应切换到使用 DomainMatrix,如问题 #21402 所示。稍后将添加更好的 Smith 标准形式 API。

矩阵中的非Expr对象

在 SymPy 1.8 及更早版本中,可以将非Expr元素放入Matrix中,矩阵元素可以是任何任意的Python对象:

>>> M = Matrix([[(1, 2), {}]]) 

这没有用,实际上不起作用,例如:

>>> M + M 
Traceback (most recent call last):
...
TypeError: unsupported operand type(s) for +: 'Dict' and 'Dict'

实现这一功能的主要原因是,SymPy 代码库中有许多 Matrix 子类希望与 polys 模块中的对象一起工作,例如。

  1. RawMatrix (见 上文) 在 solve_lin_sys 中使用,该函数是 heurisch 的一部分,也被 smith_normal_form 使用。NewMatrix 类使用域元素作为矩阵的元素,而不是 Expr

  2. NewMatrixholonomic 模块中使用,并且也使用域元素作为矩阵元素

  3. PolyMatrix 使用了 PolyExpr 的混合作为矩阵元素,并被 risch 使用。

所有这些矩阵子类在不同方面都存在问题,而引入 DomainMatrix (#20780, #20759, #20621, #19882, #18844) 为所有情况提供了更好的解决方案。之前的PR已经移除了这些其他用例对Matrix的依赖 (#21441, #21427, #21402),现在 #21496 已经弃用了在 Matrix 中使用非 Expr 的情况。

这一更改使得改进 Matrix 类的内部成为可能,但它可能影响一些下游用例,这些用例可能类似于 SymPy 代码库中使用非 Expr 元素的 Matrix。如果代码使用了非 Expr 元素的 Matrix,一个潜在的替代方案是 DomainMatrix,前提是元素类似于域元素并且可以为它们提供一个域对象。或者,如果目标只是打印支持,那么可以使用 TableForm

在不了解具体使用场景的情况下,不清楚应该建议什么作为替代方案。如果你不确定如何更新你的代码,请 提交一个issue写信到我们的邮件列表 以便我们讨论。

绘图对象的 get_segments 属性

Line2DBaseSeries 中实现的 get_segments 方法用于将两个坐标列表 xy 转换为由 Matplotlib 的 LineCollection 用于绘制线条的线段列表。

由于段落列表仅由 Matplotlib 需要(例如,Bokeh、Plotly、Mayavi、K3D 仅需要坐标列表),因此这已被移至 MatplotlibBackend 类内部。

请注意,以前,方法 get_points() 总是返回均匀采样的点,这意味着在使用 get_points() 与 Matplotlib 绘图时,某些函数未能正确绘制。

为了避免这个问题,可以使用 get_segments() 方法,该方法使用了自适应采样,并且可以与 Matplotlib 的 LineCollection 一起使用。然而,这已经被更改,现在 get_points() 也可以使用自适应采样。get_data() 方法也可以使用。

sympy.physics.matrices 中的 mdft 函数

sympy.physics.matrices.mdft() 函数已被弃用。可以用 sympy.matrices.expressions.fourier 中的 DFT 类来替代。

特别是,将 mdft(n) 替换为 DFT(n).as_explicit()。例如:

>>> from sympy.physics.matrices import mdft
>>> mdft(3) # DEPRECATED 
Matrix([
[sqrt(3)/3,                sqrt(3)/3,                sqrt(3)/3],
[sqrt(3)/3, sqrt(3)*exp(-2*I*pi/3)/3,  sqrt(3)*exp(2*I*pi/3)/3],
[sqrt(3)/3,  sqrt(3)*exp(2*I*pi/3)/3, sqrt(3)*exp(-2*I*pi/3)/3]])
>>> from sympy.matrices.expressions.fourier import DFT
>>> DFT(3)
DFT(3)
>>> DFT(3).as_explicit()
Matrix([
[sqrt(3)/3,                sqrt(3)/3,                sqrt(3)/3],
[sqrt(3)/3, sqrt(3)*exp(-2*I*pi/3)/3,  sqrt(3)*exp(2*I*pi/3)/3],
[sqrt(3)/3,  sqrt(3)*exp(2*I*pi/3)/3, sqrt(3)*exp(-2*I*pi/3)/3]])

这一更改是因为 sympy.physics 子模块应该只包含与物理相关的内容,但离散傅里叶变换矩阵是一个更普遍的数学概念,因此它更适合位于 sympy.matrices 模块中。此外,DFT 类是一个 矩阵表达式,这意味着它可以保持未求值状态并支持符号形状。

私有属性 SparseMatrix._smatDenseMatrix._mat

._mat 属性在 Matrix._smat 属性在 SparseMatrix 中已被弃用。

MatrixSparseMatrix 的内部表示在 #21626 中被更改为 DomainMatrix,因此不再可能通过暴露可变列表/字典来改变 Matrix。新的 .flat() 方法可以代替 ._mat 使用,该方法返回一个新列表,不能用于改变 Matrix 本身。新的 .todok() 方法可以代替 ._smat 使用,该方法返回一个新字典。

请注意,这些属性在 SymPy 1.9 中已经改为返回只读副本,因此任何依赖于修改它们的代码都将被破坏。此外,这些属性在技术上始终是私有的(它们以一个下划线开头),因此用户代码从一开始就不应该使用它们。

矩阵的拉普拉斯变换,noconds=False

在1.9版本之前,对一个 Matrix 调用 laplace_transform() 并设置 noconds=False(这是默认设置),结果会是一个元组矩阵:

>>> from sympy import laplace_transform, symbols, eye
>>> t, z = symbols('t z')
>>> laplace_transform(eye(2), t, z) 
Matrix([
[(1/z, 0, True),   (0, 0, True)],
[  (0, 0, True), (1/z, 0, True)]])

然而,Matrix 仅设计用于与 Expr 对象一起工作(参见上面的 矩阵中的非Expr对象)。

为了避免这种情况,可以使用 noconds=True 来移除收敛条件

>>> laplace_transform(eye(2), t, z, noconds=True)
Matrix([
[1/z,   0],
[  0, 1/z]])

或者使用 legacy_matrix=False 来返回新的行为,这将返回一个包含矩阵的单个元组,第一个参数是矩阵,收敛条件将合并为一个整体矩阵的单一条件。

>>> laplace_transform(eye(2), t, z, legacy_matrix=False)
(Matrix([
[1/z,   0],
[  0, 1/z]]), 0, True)

当此弃用被移除时,legacy_matrix=False 的行为将成为默认行为,但该标志将保持不变以确保兼容性。

版本 1.8

sympy.printing.theanocode

Theano 已经停止维护,并被分叉成一个名为 Aesara 的新项目。sympy.printing.theanocode 模块已被重命名为 sympy.printing.aesaracode,并且所有相应的函数也已被重命名(例如,theano_code 已被重命名为 aesara_code()TheanoPrinter 已被重命名为 AesaraPrinter,等等)。

版本 1.7.1

调用 sympy.stats.StochasticProcess.distribution 时使用 RandomIndexedSymbol

sympy.statsdistribution 方法 随机过程 过去接受一个 RandomIndexedSymbol(即,一个用时间戳索引的随机过程),但现在应该只用时间戳调用。

例如,如果你有

>>> from sympy import symbols
>>> from sympy.stats import WienerProcess
>>> W = WienerProcess('W')
>>> t = symbols('t', positive=True)

之前这会起作用

W.distribution(W(t)) # DEPRECATED

现在应该这样调用:

>>> W.distribution(t)
NormalDistribution(0, sqrt(t))

此更改是作为将 Basic 对象仅存储在 sympy.stats .args 中的更改的一部分进行的。详情请参见问题 #20078

版本 1.7

sympy.stats.DiscreteMarkovChain.absorbing_probabilites()

absorbing_probabilites 方法名拼写错误。应使用正确的拼写 absorbing_probabilities() (“absorbing probabilities”)。

sympy.utilities.misc.find_executable()

函数 sympy.utilities.misc.find_executable() 已被弃用。请改用标准库中的 shutil.which() 函数,该函数自 Python 3.3 起就存在于标准库中,并且功能更为强大。

sympy.diffgeom 中的可变属性

已对 sympy.diffgeom 的几个部分进行了更新,使其不再可变,这更好地匹配了 SymPy 其余部分使用的不可变设计。

  • CoordSystem 中传递符号名称的字符串已被弃用。相反,你应该明确地传递带有适当假设的符号,例如,而不是

    CoordSystem(name, patch, ['x', 'y']) # DEPRECATED
    

    使用

    CoordSystem(name, patch, symbols('x y', real=True))
    
  • 同样地,names 关键字参数已重命名为 symbols,这应该是一个符号列表。

  • Manifold.patches 属性已被弃用。补丁应单独跟踪。

  • Patch.coord_systems 属性已弃用。坐标系应单独跟踪。

  • CoordSystem.transforms 属性、CoordSystem.connect_to() 方法和 CoordSystem.coord_tuple_transform_to() 方法已被弃用。请改用 CoordSystem 类构造函数的 relations 关键字以及 CoordSystem.transformation()CoordSystem.transform() 方法(参见 CoordSystem 的文档字符串以获取示例)。

unicode 参数和属性用于 sympy.printing.pretty.stringpict.prettyFormsympy.printing.pretty.pretty_symbology.xstr 函数

sympy.printing.pretty.pretty_symbology.xstr 函数,以及 sympy.printing.pretty.stringpict.prettyFormunicode 参数和属性,都是为了支持 Python 2 的 Unicode 行为。由于 Unicode 字符串在 Python 3 中是默认的,因此这些不再需要。xstr() 应替换为 str()prettyFormunicode 参数应省略,prettyForm.unicode 属性应替换为 prettyForm.s 属性。

将参数传递给 lambdify 作为 集合

将函数参数作为集合传递给 lambdify 已被弃用。相反,请将它们作为列表或元组传递。例如,不要像这样

lambdify({x, y}, x + 2*y) # WRONG

使用

lambdify((x, y), x + 2*y) # RIGHT

这是因为集合是无序的。例如,在上面的例子中,lambidfy 无法知道它是用 {x, y} 还是 {y, x} 调用的。因此,当将参数作为集合传递时,lambdify 必须猜测它们的顺序,如果猜测错误,这将导致函数不正确。

核心操作符不再接受非 Expr 参数

核心操作符类 AddMulPow 不能再直接使用不是 Expr 子类的对象来构造。

Expr 是所有表示标量数值量的 SymPy 类的超类。例如,sinSymbolAdd 都是 Expr 的子类。然而,SymPy 中的许多对象并不是 Expr,因为它们表示其他类型的数学对象。例如,SetPolyBoolean 都不是 Expr。这些对象在 AddMulPow 中没有数学意义,因为这些类专门设计用于表示标量复数的加法、乘法和幂运算。

手动使用这样一个对象构造这些类是可能的,但它通常会创建一些随后会出错的东西。例如

Mul(1, Tuple(2)) # This is deprecated

工作并创建 Tuple(2),但这只是因为 Mul 被“欺骗”了,总是将 \(1 \cdot x = x\) 处理为 \(x\)。如果你尝试

Mul(2, Tuple(2)) # This is deprecated

它因异常而失败

AttributeError: 'Tuple' object has no attribute 'as_coeff_Mul'

因为它试图在 Tuple 对象上调用 Expr 的方法,而 Tuple 对象并没有 Expr 的所有方法(因为它不是 Expr 的子类)。

如果你想对非 Expr 对象使用 +*** 操作,请直接使用操作符,而不是使用 MulAddPow。如果需要这些操作的功能版本,你可以使用 lambdaoperator 模块。

版本 1.6

各种 sympy.utilities 子模块已移动

以下子模块已被重命名。

  • sympy.utilities.benchmarkingsympy.testing.benchmarking

  • sympy.utilities.pytestsympy.testing.pytest

  • sympy.utilities.randtestssympy.core.random

  • sympy.utilities.runtestssympy.testing.runtests

  • sympy.utilities.tmpfilessympy.testing.tmpfiles

sympy.testing.randtest

sympy.testing.randtest 已被弃用。其中的函数已移至 sympy.core.random。以下函数已被移动。

  • sympy.testing.randtest.random_complex_numbersympy.core.random.random_complex_number

  • sympy.testing.randtest.verify_numerically sympy.core.random.verify_numerically

  • sympy.testing.randtest.test_derivative_numericallysympy.core.random.test_derivative_numerically

  • sympy.testing.randtest._randrangesympy.core.random._randrange

  • sympy.testing.randtest._randintsympy.core.random._randint

在二元操作中混合 Poly 和非多项式表达式

在SymPy的早期版本中,PolyExpr 的子类,但现在已经改为仅是 Basic 的子类。这意味着一些曾经与 Poly 一起使用的东西现在已被弃用,因为它们仅设计用于与 Expr 对象一起工作。

这包括将 PolyExpr 对象使用二元操作进行组合,例如

Poly(x)*sin(x) # DEPRECATED

为此,可以根据你希望结果的类型,使用 Expr.as_poly() 将非 Poly 操作数显式转换为 Poly,或者使用 Poly.as_expr()Poly 操作数转换为 Expr

sympy.combinatorics.Permutationprint_cyclic 标志

sympy.combintorics.Permutationprint_cyclic 属性控制置换是以循环还是数组的形式打印。这可以通过设置 Permutation.print_cyclic = TruePermutation.print_cyclic = False 来实现。然而,这种控制打印的方法是糟糕的,因为它是一个全局标志,但打印不应该依赖于全局行为。

相反,用户应使用相应打印机的 perm_cyclic 标志。配置此标志的最简单方法是调用 init_printing() 时设置该标志,例如

>>> from sympy import init_printing
>>> init_printing(perm_cyclic=False) # Makes Permutation print in array form 
>>> from sympy.combinatorics import Permutation
>>> Permutation(1, 2)(3, 4) 
⎛0 1 2 3 4⎞
⎝0 2 1 4 3⎠

Permutation 文档字符串中包含有关 perm_cyclic 标志的更多详细信息。

使用 integratePoly

在SymPy的早期版本中,PolyExpr 的子类,但现在已经改为仅是 Basic 的子类。这意味着一些曾经与 Poly 一起使用的东西现在已被弃用,因为它们仅设计用于与 Expr 对象一起工作。

这包括使用 Poly 调用 integrate()Integral

要集成一个 Poly,使用 Poly.integrate() 方法。要计算积分作为一个 Expr 对象,首先调用 Poly.as_expr() 方法。

另请参见上文的 在二元操作中混合 Poly 和非多项式表达式

使用 Eq 参数创建一个不定 积分

传递一个Eq()对象给integrate()在不定积分的情况下已被弃用。这是因为如果\(f(x) = g(x)\),那么\(\int f(x)\,dx = \int g(x)\,dx\)通常不成立,这是由于任意常数(integrate不包含这些常数)的存在。

如果你想表示不定积分的等式,请明确使用 Eq(integrate(f(x), x), integrate(g(x), x))

如果你已经有一个等式对象 eq,你可以使用 Eq(integrate(eq.lhs, x), integrate(eq.rhs, x))

版本 1.5

Tensor.fun_evalTensor.__call__

TensExpr.fun_evalTensor.__call__(即调用张量来评估它)已被弃用。应使用 Tensor.substitute_indices() 方法。这一更改是因为 fun_eval 被认为是一个令人困惑的名称,并且使用函数评估被认为既令人困惑又危险。

TensorType

TensorType 类已被弃用。请改用 tensor_heads()TensorType 类除了用于更简短地创建 TensorHead 对象外,没有其他用途。

另请参见下面的 tensorhead() 函数

TensorIndexTypedummy_fmt 参数

dummy_fmt 关键字参数在 TensorIndexType 中已被弃用。设置 dummy_fmt='L' 会导致 _dummy_fmt='L_%d',这既令人困惑又使用了过时的字符串格式化。应改用 dummy_name。这一更改是因为 dummy_name 是一个更清晰的名字。

TensorIndexTypemetric 参数

metric 关键字参数在 TensorIndexType 中已被弃用。名称 “metric” 具有歧义,因为在某些地方它意味着 “度量对称性”,而在其他地方则意味着 “度量张量”。

应该使用 metric_symmetry 关键字或 TensorIndexType.set_metric() 方法。

TensorIndexTypeget_kronecker_delta()get_epsilon() 方法

get_kronecker_delta()get_epsilon() 方法是 TensorIndexType 中已弃用的方法。请分别使用 TensorIndexType.deltaTensorIndexType.epsilon 属性代替。

tensorsymmetry() 函数

sympy.tensor 中的 tensorsymmetry() 函数已被弃用。请改用 TensorSymmetry 类构造函数。

TensorSymmetrytensorsymmetry() 更受欢迎,因为后者

  1. 没有任何额外功能

  2. 涉及模糊的杨表

  3. 不是 TensorSymmetry 类的成员

tensorhead() 函数

tensorhead() 函数已被弃用,取而代之的是 tensor_heads()tensor_heads() 与其他 SymPy 名称(如 Symbolsymbols()TensorIndextensor_indices())更加一致。它也不使用杨氏表来表示对称性。

集合的 is_EmptySet 属性

is_EmptySet 属性在 Set 对象中已被弃用。请改用

from sympy import S
s is S.EmptySet

s.is_empty

区别在于,如果无法确定集合是否为空,s.is_empty 可能会返回 None

ProductSet(iterable)

将单个可迭代对象作为第一个参数传递给 ProductSet 已被弃用。从可迭代对象创建产品集应使用 ProductSet(*iterable),或作为每个单独的参数。例如

>>> from sympy import ProductSet
>>> sets = [{i} for i in range(3)]
>>> ProductSet(*sets)
ProductSet({0}, {1}, {2})
>>> ProductSet({1, 2}, {1})
ProductSet({1, 2}, {1})

这样做是因为集合本身可以是可迭代的,并且允许集合的集合。但从数学上讲,单个集合的乘积集应该是该集合本身(或者更准确地说,是该集合元素的1元组集合)。自动解嵌套单个可迭代对象使得无法表示此对象,并且在传递1个参数时使得 ProductSet 无法正确泛化。另一方面,如果第一个参数是集合而不是其他类型的可迭代对象(这是在已弃用的代码路径中当前所做的),则会导致混乱的行为。

sympy.physics.mechanics 中的 set_potential_energy 方法

set_potential_energy() 方法是 sympy.physics.mechanics.particle.Particlesympy.physics.mechanics.rigidbody.RigidBody 中已弃用的方法。

相反,应该设置 Particle.potential_energyRigidBody.potential_energy 属性来设置势能,例如

P.potential_energy = scalar

这一更改是为了更加符合 Python 风格,通过使用 @property 方法的设置器和获取器,而不是显式的 set_ 方法。

ConditionSet 中使用集合作为条件

在 ConditionSet 中使用集合作为条件已被弃用。应改用布尔值。这是因为条件在数学上是一个布尔值,而在此上下文中集合的含义是不明确的。

要修复这个弃用警告,请替换

ConditionSet(symbol, set_condition)

ConditionSet(symbol, And(*[Eq(lhs, 0) for lhs in set_condition]))

例如,

ConditionSet((x, y), {x + 1, x + y}, S.Reals) # DEPRECATED

将会变成

ConditionSet((x, y), Eq(x + 1, 0) & Eq(x + y, 0), S.Reals)

sympy.polys.multivariate_resultants.DixonResultantmax_degreeget_upper_degree 属性

DixonResultantmax_degree 属性和 get_upper_degree() 方法已被弃用。详情请参见问题 #17749

Lambda 的第一个参数为非元组的可迭代对象

使用非元组作为 Lambda 的第一个参数已被弃用。如果你有一个非元组,请先将其转换为元组,例如 Lambda(tuple(args), expr)

这样做是为了让 Lambda 能够支持一般的元组解包,例如

>>> from sympy import Lambda, symbols
>>> x, y, z = symbols('x y z')
>>> f = Lambda((x, (y, z)), x + y + z)
>>> f(1, (2, 3))
6

evaluate 标志用于 differentiate_finite

differentiate_finite()evaluate 标志已被弃用。

differentiate_finite(expr, x, evaluate=True) 在计算差分之前展开中间导数。但这通常不是你想要的,因为它不满足乘积法则。

如果你确实想要这种行为,你可以通过以下方式模拟它:

diff(expr, x).replace(
    lambda arg: arg.is_Derivative,
    lambda arg: arg.as_finite_difference())

参见关于问题 #17881 的讨论。

版本 1.4