Python 破折号输入字典键和eval

Python 破折号输入字典键和eval,python,Python,在我被“eval is evil”人群打死之前,在这种情况下,这是一种必要的邪恶,我无法改变它。Eval有它的用途,在严格控制的环境中,它非常强大 然而,我有一个没有明显解决方案的问题,我希望跳出框框思考 >>> mydict = {"a-b": "woohoo"} >>> mydict["a-b"] 'woohoo' >>> eval('mydict["a-b"]') 'woohoo' >>> eval('a-b', my

在我被“eval is evil”人群打死之前,在这种情况下,这是一种必要的邪恶,我无法改变它。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
mydict={“a-b”:“woohoo”} >>>mydict[“a-b”] “呜呼” >>>评估('mydict[“a-b”]”) “呜呼” >>>评估('a-b',mydict) 回溯(最近一次呼叫最后一次): 文件“”,第1行,在 文件“”,第1行,在 NameError:未定义名称“a” 不幸的是,最后一个案例是我被迫使用的,显然它不起作用。你知道如何将表达式求值到我的“全局”或“局部”对象中,而不让它将-解释为减号运算符吗?“globals”对象中的某些键的键名中确实有破折号,这是我无法控制的数据

请参阅下面的评论

  • 数据来自外部来源。我根本无法指令或控制数据的格式
  • 我正在评估的“子句”来自存储的用户配置
这是一个更大系统的一部分,用户可以通过api将JSON数据推入,我们将数据作为字典进行内部处理,然后对数据应用某些规则。这些规则由管理员从web界面以配置形式提供

最终,我需要允许用户给我一个(可能很复杂的)python一行程序,并根据字典对其进行评估。这不正是
eval
的目的吗?如果有更好的方法,我不能听写数据的格式,必须允许用户给我一个带评估的字符串?Eval很神奇,因为它可以让用户做很多很酷的事情,比如使用
.get()
len()
,但显然它也有缺点,就像前面提到的无法区分或逃避
-
一样


谢谢

在求值过程中,您试图将字符串“a-b”作为符号。传统上,这不起作用,因为“-”(连字符)不是单词。符号名称中只能使用[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'
>>> 
在这里,我使用了加拿大音节最后一个简短的水平笔划(尽管这显然是对该代码意图的滥用)。有关此方法的更多信息,请参阅帖子

我需要允许用户给我一个(可能很复杂的)python版本 划线并对照字典对其进行评估

如果是这样的话,
a
b
不应该是解决问题的字典的一部分吗:

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

不要使用
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版本。

我们需要更多的上下文。为什么您必须使用
eval
mydict
“a-b”
来自哪里?是否允许您更改mydict的结构?您可以更改此系统的哪些部分
eval
显然不适合您希望它执行的任务。您是否知道这样使用
eval
会变异
mydict
,即使您计算的表达式是非变异的?它在mydict中插入一个新的
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu内置项
,这可能是非常不受欢迎的。@user23571121)eval是我能找到的唯一有效的方法2)数据来自不受控制的外部源3)我根本无法更改结构4)我可以编写任何我喜欢的代码来实现更新问题中所述的目标。是的,我很确定eval对它进行了变异,事实上这很好,因为我们希望在求值中允许尽可能多的python关键字。谢谢既然您想要解析的不是Python,而是语法非常相似的DSL,为什么不自己编写一个解析器来读取您的新语言并生成Python代码,然后您就可以
eval
?令人厌烦,但完全可行。(当然,还是有人会为了邪恶而使用你的代码,但公平地说,他们会给你上一堂重要的课。听起来你不会从其他方面学到任何东西。:-)我可能不太清楚。来自供应商的文档中的实际密钥的格式为“a-b”,例如
{“item count”:50}