Pint自定义单位时能否处理带括号的复杂运算?求解决方案
问题
首次在Pint的UnitRegistry中创建蔗糖相关的自定义单位(比重、白利度),目前仅用到加减乘运算,但带括号的运算顺序导致解析失败,想知道Pint是否支持基础运算外的复杂计算。
已定义比重单位:
PINT_UNIT_REGISTER = UnitRegistry() PINT_UNIT_REGISTER.define('SpecificGravity = [Sucrose] = sg')
尝试定义白利度单位时出错:
PINT_UNIT_REGISTER.define('Brix = (((182.4601 * sg - 775.6821) * sg + 1262.7794) * sg - 669.5622) = bx')
错误信息:
File "/Users/aaronpaxson/PycharmProjects/stonesrivermeadery-webroot/stonesrivermeadery/settings.py", line 181, in <module> PINT_UNIT_REGISTER.define('Brix = (((182.4601 * sg - 775.6821) * sg + 1262.7794) * sg - 669.5622) = Bx') File "/Users/aaronpaxson/PycharmProjects/stonesrivermeadery-webroot/venv/lib/python3.9/site-packages/pint/facets/plain/registry.py", line 428, in define self._helper_dispatch_adder(definition) File "/Users/aaronpaxson/PycharmProjects/stonesrivermeadery-webroot/venv/lib/python3.9/site-packages/pint/facets/plain/registry.py", line 447, in _helper_dispatch_adder raise TypeError( TypeError: No loader function defined for UnhandledParsingError
解决方法
Pint的define方法仅支持线性换算关系的单位定义,不支持这种嵌套括号的多项式非线性表达式,这是解析失败的核心原因。针对白利度(Brix)和比重(sg)的非线性换算需求,可采用以下两种可行方案:
方案1:注册双向转换函数
利用Pint的register_transformation方法,手动实现比重与白利度的双向转换逻辑:
from pint import UnitRegistry PINT_UNIT_REGISTER = UnitRegistry() PINT_UNIT_REGISTER.define('SpecificGravity = [Sucrose] = sg') PINT_UNIT_REGISTER.define('Brix = [Sucrose] = bx') # 比重转白利度 def sg_to_bx(sg_quantity): sg = sg_quantity.magnitude return ((182.4601 * sg - 775.6821) * sg + 1262.7794) * sg - 669.5622 # 白利度转比重(数值迭代求解三次方程,可根据需求优化精度) def bx_to_sg(bx_quantity): bx = bx_quantity.magnitude sg = 1.0 for _ in range(10): current_bx = ((182.4601 * sg - 775.6821) * sg + 1262.7794) * sg - 669.5622 # 用导数做牛顿迭代加速收敛 sg += (bx - current_bx) / (547.3803 * sg**2 - 1551.3642 * sg + 1262.7794) return sg # 注册双向转换规则 PINT_UNIT_REGISTER.register_transformation( PINT_UNIT_REGISTER.sg, PINT_UNIT_REGISTER.bx, sg_to_bx ) PINT_UNIT_REGISTER.register_transformation( PINT_UNIT_REGISTER.bx, PINT_UNIT_REGISTER.sg, bx_to_sg )
方案2:给Quantity类扩展自定义转换方法
如果不需要全局单位转换规则,可直接给Pint的Quantity对象添加转换方法:
from pint import UnitRegistry, Quantity PINT_UNIT_REGISTER = UnitRegistry() PINT_UNIT_REGISTER.define('SpecificGravity = [Sucrose] = sg') PINT_UNIT_REGISTER.define('Brix = [Sucrose] = bx') def to_bx(self): if self.units != PINT_UNIT_REGISTER.sg: raise ValueError("仅支持比重(sg)单位转换为白利度(bx)") sg = self.magnitude bx_val = ((182.4601 * sg - 775.6821) * sg + 1262.7794) * sg - 669.5622 return Quantity(bx_val, PINT_UNIT_REGISTER.bx) def to_sg(self): if self.units != PINT_UNIT_REGISTER.bx: raise ValueError("仅支持白利度(bx)单位转换为比重(sg)") bx = self.magnitude sg = 1.0 for _ in range(10): current_bx = ((182.4601 * sg - 775.6821) * sg + 1262.7794) * sg - 669.5622 sg += (bx - current_bx) / (547.3803 * sg**2 - 1551.3642 * sg + 1262.7794) return Quantity(sg, PINT_UNIT_REGISTER.sg) # 给Quantity类绑定方法 Quantity.to_bx = to_bx Quantity.to_sg = to_sg
使用示例
# 比重转白利度 sg_val = PINT_UNIT_REGISTER.Quantity(1.04, 'sg') bx_val = sg_val.to_bx() print(bx_val) # 白利度转比重 bx_val = PINT_UNIT_REGISTER.Quantity(10, 'bx') sg_val = bx_val.to_sg() print(sg_val)
内容的提问来源于stack exchange,提问作者Aaron Paxson
相关产品推荐
相关产品推荐

