直接传入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
相关产品推荐
相关产品推荐

