function S = dsolve(eqs, conds)
    % S = symdsolve(eq)
    % S = symdsolve(eq, conds)
    % S = symdsolve(eqs, conds)
    % 求解常微分方程组，eqs是符号等式（sp.Eq）或其组成的元胞数组，fn是需要求解的函数符号或其组成的元胞数组，conds是求解的初值条件，是符号等式（要求左边是替换对应求解符号函数的表达式，右边是具体的值）。
    % 例子：
    %% 求解一阶微分方程
    % Input [1] >> a = syms('a'); f = sym('f(t)');
    % Input [2] >> eq = symeq(f.diff(t), a*f);
    % Input [3] >> symdsolve(eq)
    % Eq(f(t), C1*exp(a*t))
    %% 加上初值条件：
    % Input [4] >> dsolve(eq, symeq(f.subs(t, 0), 5))
    % Eq(f(t), 5*exp(a*t))
    %% 求解二阶微分方程：
    % Input [5] >> eq = symeq(f.diff(t, 2), a*f);
    % Input [6] >> symdsolve(eq)
    % Eq(f(t), C1*exp(-sqrt(a)*t) + C2*exp(sqrt(a)*t))
    %% 加上两个初值条件：
    % Input [7] >> df = f.diff(t);
    % Input [8] >> symdsolve(eq, {symeq(f.subs(t, 0), 0), symeq(df.subs(t, 0), 1)})
    % Eq(f(t), exp(sqrt(a)*t)/(2*sqrt(a)) - exp(-sqrt(a)*t)/(2*sqrt(a)))
    %% 求解二元常微分方程组：
    % Input [9] >> y = sym('y(t)'); z = sym('z(t)');
    % Input [10] eq1 = symeq(y.diff(t), z);
    % Input [11] eq2 = symeq(z.diff(t), -y);
    % Input [12] symdsolve({eq1,eq2})
    % 此时会返回 Python 列表：
    % [Eq(y(t), C1*sin(t) + C2*cos(t)), Eq(z(t), C1*cos(t) - C2*sin(t))] 
    % S = dsolve(eq)
    % S = dsolve(eq, conds)
    % S = dsolve(eqs, conds)
    % 求解常微分方程组，适配自定义类对象（Eq/Expr/Function）
    % 输入：
    %   eqs   - 自定义Eq类对象（单个）/Eq类对象元胞数组（多个），表示微分方程
    %   conds - 可选，自定义Eq类对象（单个）/Eq类对象元胞数组（多个），表示初值条件
    % 输出：
    %   S     - 求解结果，单个解返回Eq类对象，多个解返回Eq类对象元胞数组
    % 核心：通过getObj()方法获取类对象的sympy原生Python对象指针
    
    % ===================== 步骤1：初始化sympy环境 =====================
    py = pyroot();
    sp = sympy__sp();
    % ===================== 步骤2：预处理微分方程eqs（适配类对象） =====================
    if iscell(eqs)
        % 情况2：类对象元胞数组，遍历转换为sympy原生对象列表
        eqs_sp = pylist;
        for i = 1:length(eqs)
            if ~isa(eqs{i}, 'sympy.Eq') && ~isa(eqs{i}, 'sympy.Expr')
                error('方程必须是sympy.Eq或sympy.Expr类对象！');
            end
            eqs_sp.append(getObj(eqs{i}));  % 核心：getObj获取py对象
        end
    elseif 1 % bug needs fix
        % 情况1：单个自定义类对象（Eq/Expr），通过getObj获取sympy原生对象
        eqs_sp = getObj(eqs);
    else
        error('eqs必须是sympy.Eq/Expr类对象（单个）或其元胞数组！');
    end

    % ===================== 步骤3：处理初值条件并求解 =====================
    if nargin == 1
        % 无初值条件：直接求解
        S_py = sp.dsolve(eqs_sp);
    elseif nargin == 2
        % 有初值条件：构建ics字典并求解
        if ~iscell(conds)
            conds = {conds};  % 统一转为元胞数组处理
        end
        
        ics = py.dict();  % 初始化sympy的ics字典
        for i = 1:length(conds)
            tmp_cond = conds{i};
            % 校验条件对象类型
            % 核心：通过getObj获取条件等式的sympy原生对象，再提取lhs/rhs的py对象
            cond_sp = getObj(tmp_cond);
            lhs_sp = cond_sp.lhs;  % sympy原生lhs对象
            rhs_sp = cond_sp.rhs;  % sympy原生rhs对象
            ics{lhs_sp} = rhs_sp;  % 填充ics字典
        end
        
        % 调用sympy.dsolve，传入ics参数
        S_py = sp.dsolve(eqs_sp, pyargs('ics', ics));
    end

    % ===================== 步骤4：将sympy结果封装为自定义类对象 =====================
    if py.isinstance(S_py, sp.Eq)
        % 情况1：单个解（sympy.Eq对象）→ 封装为自定义Eq类对象
        S = sympy.Expr(S_py.rhs);
    elseif py.isinstance(S_py, py.list) || py.isinstance(S_py, py.tuple)
        % 情况2：多个解（列表/元组）→ 封装为Eq类对象元胞数组
        S = {};
        sol_list = py.list(S_py);  % 转为Python列表方便遍历
        for i = 1:py.len(sol_list)
            sol_sp = sol_list{i-1};  % Python索引从0开始
            if py.isinstance(sol_sp, sp.Eq)
                S{end+1} = sympy.Eq(sol_sp);  % 封装为Eq类
            else
                S{end+1} = sympy.Expr(sol_sp);  % 非等式则封装为Expr类
            end
        end
    else
        % 情况3：其他结果类型（如纯表达式）→ 封装为Expr类对象
        S = sympy.Expr(S_py);
    end
end