活动弃用列表

此页面列出了 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).*<regex matching the warning message> 是匹配警告消息的正则表达式。例如,要过滤关于 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.13

弃用的 mechanics Body 类

Body 类在 sympy.physics.mechanics 模块中已被弃用。它是为了支持关节框架而引入的。但是,它会导致一些问题,因为它同时表示刚体和粒子。 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

弃用的 mechanics JointsMethod

JointsMethod 类在 sympy.physics.mechanics 模块中已被弃用。它是为了支持关节框架而引入的,但由于其设计中的局限性,它已被完全替换。以前,可以使用 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 的未来版本中删除。对这些类进行子类化已被弃用,任何进行此操作的代码都应该更改为不再对它们进行子类化。

使用这些类与 isinstance(如 isinstance(M, MatrixCommon))也被弃用。任何执行此操作的代码都应该更改为使用 isinstance(M, Matrixbase),它也能与之前的 SymPy 版本一起使用。

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

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

sympify() 中的字符串回退

sympify 函数以前会将无法识别的对象转换为字符串,然后重试 sympification。这在 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 将在某个时候成为所有库代码的默认设置,但这是一个 更难进行的更改

  • 它会导致安全问题,因为字符串会被 eval,并且对象可以在其 __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 仍然会生成一个列表,但现在会发出弃用警告。

不要使用 .rep,而是使用 DMP.to_list() 方法,该方法返回一个等效的列表。

>>> 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 的清晰性,以及在重写装置中包含此功能会导致当期望布尔值的节点被重写为表达式时出现错误,因此我们认为没有必要提供替代的属性/方法。

弃用 Plot 类中的 markers、annotations、fill、rectangles

属性 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

移动力学函数

随着 Inertiasympy.physics.mechanics 模块中的负载对象等一些新对象的引入,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

模整数域的元素具有一个 to_int() 方法,该方法自 SymPy 1.13 起已弃用。

>>> # 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 参数指定此轴。这种设置的一个优势是,人们可以更准确地定义从父体到子体的变换。

例如,假设您想要一个 PinJoint,它使子体绕 parent.z 轴和 -child.z 轴旋转。之前指定此关节的方法是

>>> 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_*

为了避免与具有与模块名称相似的名称的函数发生可能的命名和制表符完成冲突,所有名称以 conv_* 开头的模块在 sympy.tensor.array.expressions 中已重命名为 from_*

新的 Mathematica 代码解析器

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

Mathematica 解析器的 additional_translations 参数在 parse_mathematica 中不可用。应该在转换后使用 SymPy 的 .replace( ).subs( ) 方法在输出表达式上指定将 Mathematica 表达式转换为 SymPy 表达式的附加转换规则。如果转换器无法识别 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

  • use

已移动到不同的 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)

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

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。因此,numsamples参数不再需要用于sample()

sympy.polys.solvers.RawMatrix

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

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

矩阵中的非Expr对象

在SymPy 1.8及更早版本中,可以在Expr矩阵中放置非Expr元素,矩阵元素可以是任何任意的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. NewMatrix用于holonomic模块,并且还使用域元素作为矩阵元素。

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

所有这些矩阵子类都以不同的方式被破坏,并且引入了DomainMatrix#20780#20759#20621#19882#18844)为所有情况提供了更好的解决方案。以前的PR已删除了这些其他用例对Matrix的依赖性(#21441#21427#21402),现在#21496已弃用在Matrix中使用非Expr

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

在不知道用例的更多信息的情况下,不清楚在这里建议什么作为替代方案。如果您不清楚如何更新代码,请打开一个问题写信给我们的邮件列表,以便我们进行讨论。

绘图对象的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类。

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

>>> 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 的内部表示已更改为 DomainMatrix (在 #21626 中),因此不再可能通过暴露可变列表/字典来修改 Matrix。 您可以使用新的 .flat() 方法来替代 ._mat,该方法返回一个新的列表,不能用来修改 Matrix 本身。 您可以使用 .todok() 方法来替代 ._smat,该方法返回一个新的字典。

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

带有 noconds=False 的 Matrix 的 laplace_transform

在 1.9 版本之前,在带有 noconds=False (默认值) 的 laplace_transform() 上调用 Matrix 会导致一个元组矩阵。

>>> 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 对象(见上文的 Non-Expr objects in a Matrix)。

为了避免这种情况,请使用 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

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

sympy.stats 随机过程distribution 方法过去可以接受一个 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
    

    use

    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() 方法已被弃用。 相反,请使用 relations 关键字到 CoordSystem 类构造函数以及 CoordSystem.transformation()CoordSystem.transform() 方法(请参阅 CoordSystem 的文档字符串以获取示例)。

sympy.printing.pretty.stringpict.prettyFormunicode 参数和属性以及对 sympy.printing.pretty.pretty_symbology.xstr 函数的 unicode 参数和属性

sympy.printing.pretty.pretty_symbology.xstr 函数和对 sympy.printing.pretty.stringpict.prettyFormunicode 参数和属性都存在,以支持 Python 2 的 Unicode 行为。 由于 Unicode 字符串在 Python 3 中是默认值,因此它们不再需要。 xstr() 应该被简单地替换为 str(),对 prettyFormunicode 参数应该被省略,prettyForm.unicode 属性应该被替换为 prettyForm.s 属性。

将参数作为 set 传递给 lambdify

将函数参数作为集合传递给 lambdify 已被弃用。请改用列表或元组传递它们。例如,不要使用:

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

use

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\) 进行处理来“欺骗”。如果你尝试使用:

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

它会抛出一个异常

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

因为它试图在 Tuple 对象上调用 Expr 的方法,而该对象没有所有 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 对象。

这包括使用 integrate()IntegralPoly

要积分 Poly,请使用 Poly.integrate() 方法。要将积分计算为 Expr 对象,请先调用 Poly.as_expr() 方法。

另见上面在二元运算中混合多项式和非多项式表达式

使用 Eq 参数创建不定 Integral

在不定积分的情况下,将 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 参数

传递给 TensorIndexTypedummy_fmt 关键字参数已被弃用。将 dummy_fmt='L' 设置为 _dummy_fmt='L_%d' 会令人困惑,并且使用过时的字符串格式。请改用 dummy_name。之所以进行此更改是因为 dummy_name 的名称更清晰。

传递给 TensorIndexTypemetric 参数

传递给 TensorIndexTypemetric 关键字参数已被弃用。“metric” 的名称模棱两可,因为它在某些地方表示“度量对称性”,而在另一些地方则表示“度量张量”。

请改用 metric_symmetry 关键字或 TensorIndexType.set_metric() 方法。

TensorIndexTypeget_kronecker_delta()get_epsilon() 方法

TensorIndexTypeget_kronecker_delta()get_epsilon() 方法已被弃用。请改用 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 属性

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

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 元组的集合)。自动取消单个可迭代对象的嵌套会使其无法表示此对象,并导致 ProductSet 在传递 1 个参数时无法正确推广。另一方面,如果第一个参数是集合,则将其与其他类型的可迭代对象区别对待(这正是当前在弃用代码路径中所做的事情),这是一种令人困惑的行为。

sympy.physics.mechanics 中的 set_potential_energy 方法

sympy.physics.mechanics.particle.Particlesympy.physics.mechanics.rigidbody.RigidBodyset_potential_energy() 方法已被弃用。

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

P.potential_energy = scalar

之所以进行此更改是为了使代码更加 Pythonic,使用 @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

differentiate_finiteevaluate 标志

differentiate_finite()evaluate 标志已弃用。

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

如果你真的想要这种行为,你可以用以下方法模拟它:

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

请参见 issue #17881 上的讨论。

版本 1.4