暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

eval()遭遇"NameError: name 'true' is not defined"

青衣十三楼飞花堂 2019-06-21
5561

有个别人开发的Python程序,某些人一直用得好好的,某天突然提示:


"NameError: name 'true' is not defined"

受人之托尝试解决。我不是Python达人,临时抱佛脚,用printf大法排查。关于这个,说个题外话:


《别再用print输出来调试代码了》
https://github.com/cool-RR/PySnooper
(可以pip安装)


后来排查到是用eval()解析JSON格式的字符串时报错。合理猜测,被解析的JSON格式字符串于某日开始发生了变化。

这是个老问题,先说解决办法。



eval( s )

改成

eval( s, {"true":True,"false":False,"null":None} )


话说用eval()太危险,要是数据源插个格式化、删除、远控或者信息收集回传功能代码下来,用这个Python程序的人可怎么活啊?对付前三者,可以用虚拟机,提前建好快照以防万一,对付第四者就要注意了,不要在本地任何文件中留下个人信息。言尽于此,自求多福。

处理JSON格式字符串,一般有两种办法,eval()和json.loads(),下面对二者进行一些对比。

eval()、json.loads()均可将JSON格式的str转成dict、list等object。




eval()、json.loads()相当于对str反序列化,相应的序列化操作是json.dumps(),即将dict、list等object转成str。

eval()与json.loads()并不等价,eval()功能强于json.loads(),也更不安全,事实上所有语言的eval()都是一个危险功能,尤其形参s为他人所控时。eval()处理形参s时,先将s理解成Python代码,对之解释执行,这会将s转成PVM(Python虚拟机)字节码。json.loads()只对形参s进行字符串解析处理,消耗的资源小于eval()。

让我们把目标局限于对str反序列化。json.loads()不认str内部的单引号,只认双引号,eval()无此限制。




Python2的json.loads()将双引号中的字符串转成unicode而不是str,这是个坑。




Python3的json.loads()将双引号中的字符串转成str,与eval()在此动作上没有区别。据我实测,处理中文时json.loads()兼容性不如eval(),所以有些人还是冒着大风险使用eval()。

eval()与json.loads()另有一个坑爹的区别。



json.loads()认true、false、null这种写法,反序列化之后转成True、False、None。eval()不认,报错:

NameError: name 'true' is not defined

Python2、Python3的eval()都有这病,可以治。



上例给eval()指定了第二形参globals,也可以使用第三形参locals。



强烈建议在Python3中使用json.loads(),尽最大可能避免使用eval()。


文章转载自青衣十三楼飞花堂,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论