字典键中的短划线和评估

时间:2016-06-09 18:59:54

标签: python

在我被“eval to be death”打败之前,他就是邪恶的'人群,在这种情况下它是一个必要的邪恶,我无法改变它。 Eval有它的用途,在严格控制的环境中,它非常强大。

然而,我遇到了一个没有明显解决方案的问题,我希望能够超越思维。

>>> mydict = {"a-b": "woohoo"}
>>> mydict["a-b"]
'woohoo'
>>> eval('mydict["a-b"]')
'woohoo'
>>> eval('a-b', mydict)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<string>", line 1, in <module>
NameError: name 'a' is not defined

不幸的是,最后一个案例是我被迫使用的案例,显然它不起作用。任何想法如何将表达式评估到我的&#39;全局变量&#39;或者&#39;当地人&#39;对象,而不是它解释 - 作为减号运算符?我的&#39;全局变量中的一些键。对象在键名中有破折号,这是我无法控制的数据。

以下评论。

  • 数据来自外部来源。我根本无法决定或控制数据的格式。
  • &#39;条款&#39;我正在通过存储的用户配置向我发送评估。

这是更大系统的一部分,用户可以通过api推送JSON数据,我们在内部将数据作为字典处理,然后我们将某些规则应用于数据。管理员从Web界面提供规则作为配置。

最终,我需要允许用户给我一个(可能是复杂的)python one liner并根据字典对其进行评估。那不就是eval的用途吗?如果有一个更好的方法,我不能指示数据的格式,并且必须允许用户给我一个评估的字符串? Eval很棒,因为它让用户可以做很多很酷的事情,比如使用.get()len(),但显然它有缺点,就像前面提到的无法区分或逃脱{{1} }。

谢谢!

2 个答案:

答案 0 :(得分:1)

在评估过程中,您尝试将字符串“a-b”作为符号。传统上,这不起作用,因为“ - ”(连字符)不是 word 。只能在符号名称中使用[A-Za-z0-9_]( word )字符。将连字符更改为下划线可以正常工作:

>>> mydict = {"a_b": "woohoo"}
>>> eval('a_b', mydict)
'woohoo'
>>> 

但是,在Python3中,可以在符号中使用许多Unicode字符,有些可能是ASCII连字符的适当替换:

>>> mydict = {"aᐨb": "woohoo"}
>>> eval('aᐨb', mydict)
'woohoo'
>>> 

在这里,我使用加拿大音节最后的短水平笔画(虽然显然是滥用此代码的预期用途。)有关此方法的更多信息,请参阅帖子What Unicode symbols are accepted in Python3 variable names?

  

我需要允许用户给我一个(可能是复杂的)python   班轮并根据字典对其进行评估。

如果是这种情况,那么ab不应该成为该字典的一部分,这可以解决问题:

>>> mydict = {"a": 34, "b": 13}
>>> eval('a-b', mydict)
21

答案 1 :(得分:1)

不要将mydict用作评估表达式的全局变量dict,而是让用户以dict的形式访问它:

eval(user_expression, {'data': mydict})

然后用户使用

之类的表达式访问它
data['a-b']

而不是尝试使用a-b作为变量名称,并且需要以某种方式打破Python解析器。如果您可能拥有JSON数组或其他JSON类型而不是JSON对象,那么这一点特别好,因为Python列表不能用作eval的全局变量环境。

如果你想让语法更好一点,你可以给用户类似Javascript的点属性访问:

class ItemsAsAttributesDict(dict):
    def __getattr__(self, name):
        return self[name]

# when loading the JSON
dict = json.loads(json_string, object_hook=ItemsAsAttributesDict)

然后就像在Javascript中一样,像data['a']这样的dict条目可以作为data.a访问,但像data['a-b']这样的条目仍然需要括号表示法。

如果您使用mydict作为全局变量dict,则用户必须使用globals()来访问不是有效变量名的密钥:

globals()['a-b']

请注意,使用eval会打开讨厌的攻击媒介。人们会认为这些查询是安全的,他们会评估来自不受信任来源的查询,然后有人会要求提供

的价值
__import__('os').system('arbitrary_evil_command')

每个人都会恨你。

此外,使用eval将您的程序与Python语法联系起来。您可能会将其移植到任何其他语言,特别是因为用户将依赖于列表推导和您可能没有预料到的其他Python功能。您甚至可能很难在Python版本之间进行转换,或者支持不同的Python版本。

相关问题