1

在这个问题中,“单位”是指物理量中使用的“计量单位”。

我想安全地解析包含物理量(例如'23 kg')的不受信任的用户输入字符串。我想使用 Python 可用的包之一(如UnumQuantities),因为它们负责单位之间的转换、数学表达式中包含的单位的简化、基本单位的缩减,但我找不到一种方法将字符串转换为(上述包的)对象,而不是 using eval(),这似乎不安全。

例如,假设kgandcm绑定到Unum包对象并引用千克和厘米单位,我需要一个能够从字符串返回Unum包对象的函数,例如:

cast_to_unit("100 kg/cm")

或者

"100 kg/cm".asUnit()

  1. 有没有办法从提到的包中获得这样的功能?如果不,
  2. 有没有安全使用的方法 eval()?如果不,
  3. 是否有任何其他包(甚至不是在 Python 中)具有这样的功能?
4

2 回答 2

5

快速浏览一下Unum's文档,您似乎应该能够通过以下方式执行以下操作eval

from unum.units import * # Load a number of common units.
distance = 100*m
time = eval('9.683*s')
speed = distance / time
print(speed)

但是,如果您这样做,请确保您阅读文档eval以及如何传递本地和全局映射以限制命名空间访问以使其更安全——特别是如果您计划将此代码发布到外部世界。您可能还想检查下划线 ( _) 的字符串,并且不允许将它们传递给eval.


正如kindall所指出的,导入*通常不是很好的风格。这是一个更安全的替代方案,可以避免从以下位置导入*

import unum.units
safe_dict = dict((x,y) for x,y in unum.units.__dict__.items() if '__' not in x)
safe_dict['__builtins__'] = None

def convert(s):
    if '__' in s:
       raise ValueError("Won't do this with underscores...it's unsafe")
    return eval(s,safe_dict)

请注意,我删除了这篇文章__中提倡的方法

于 2012-11-28T18:40:07.793 回答
1

注意:这不是一个确定的答案。请将其视为如何构建与您所要求的类似的东西的示例。使用Unum模块确实是一个更好的主意,除非它不符合您的需要。

您可以自己编写一些东西,像这样重载运算符:

>>> class Unit(object):
    def __init__(self, unit_name):
        self.unit_name = unit_name
        self.unit_qty = 1
    def __div__(self, other):
        result = self.__class__(self.unit_name)
        result.unit_qty = self.unit_qty / other
        return result
    def __rdiv__(self, other):
        result = self.__class__(self.unit_name)
        result.unit_qty = other / self.unit_qty
        return result
    def __mul__(self, other):
        result = self.__class__(self.unit_name)
        result.unit_qty = self.unit_qty * other
        return result
    def __rmul__(self, other):
        return self.__mul__(other)
    def __repr__(self):
        return '%s %s' % (self.unit_qty, self.unit_name)


>>> kg = Unit('kg')
>>> 100 * kg
100 kg
>>> 100 * 10 * kg
1000 kg
>>> (10 * 20 * kg) / 2
100 kg

然后你可以用它eval()来评估表达式(如“ 100*kg”),但要小心。可能这应该可以帮助您摆脱一些问题:

eval('100*kg', {'__builtins__': {}, 'kg': Unit('kg')})
于 2012-11-28T18:46:02.777 回答