You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

直接传入Chem.MolFromSmiles与先存变量再传入的结果差异原因

RDKit TPSA计算结果不一致的原因分析

问题重现

你遇到的问题是:同一个Mol对象先后调用Descriptors.TPSA函数,传入不同参数却得到相同结果;而每次创建新Mol对象调用则能得到正确结果。代码示例如下:

from rdkit.Chem import Descriptors
from rdkit import Chem

# 直接创建Mol传入的方式(结果正确)
print(Descriptors.TPSA(Chem.MolFromSmiles('OC(=O)P(=O)(O)O')))
# 输出: 94.83
print(Descriptors.TPSA(Chem.MolFromSmiles('OC(=O)P(=O)(O)O'), includeSandP=True))
# 输出: 104.64000000000001

# 先存入变量再传入的方式(第二次结果错误)
mol = Chem.MolFromSmiles('OC(=O)P(=O)(O)O')
print(Descriptors.TPSA(mol))
# 输出: 94.83
print(Descriptors.TPSA(mol, includeSandP=True))
# 输出: 94.83

原因解析

RDKit的TPSA函数会将计算结果缓存到传入的Mol对象内部(通过添加_tpsa属性实现)。当你第一次调用TPSA(mol)时,函数使用默认参数(includeSandP=False)计算得到结果并缓存;第二次调用时,即使传入了includeSandP=True,函数会优先读取已存在的缓存值,而不会重新计算,导致结果错误。

而直接传入Chem.MolFromSmiles(...)的方式每次都会创建全新的Mol对象,没有缓存值,因此每次都会根据传入的参数重新计算,得到正确结果。

官方文档说明(翻译)

TPSA(拓扑极性表面积)描述符的实现细节:
计算TPSA时,RDKit会将结果缓存到分子对象的属性中,后续调用若未明确触发重新计算,会直接使用缓存值。默认计算逻辑不包含硫、磷原子的极性表面积贡献;当设置includeSandP=True时,会额外计入这两类原子的贡献。

解决方案

你可以通过以下几种方式避免这个问题:

  • 每次调用TPSA时创建新的Mol对象:
    print(Descriptors.TPSA(Chem.MolFromSmiles('OC(=O)P(=O)(O)O'), includeSandP=True))
    
  • 清除Mol对象的缓存属性后再重新计算:
    mol = Chem.MolFromSmiles('OC(=O)P(=O)(O)O')
    print(Descriptors.TPSA(mol))
    # 删除缓存的TPSA属性
    if '_tpsa' in mol.__dict__:
        del mol.__dict__['_tpsa']
    print(Descriptors.TPSA(mol, includeSandP=True))
    # 输出: 104.64000000000001
    
  • 创建Mol对象的副本传入计算:
    mol = Chem.MolFromSmiles('OC(=O)P(=O)(O)O')
    print(Descriptors.TPSA(mol))
    print(Descriptors.TPSA(Chem.Mol(mol), includeSandP=True))
    # 输出: 104.64000000000001
    

内容的提问来源于stack exchange,提问作者Tarquinius

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 22:50:42