将ast.literal_eval与sys.argv结合使用

时间:2015-02-12 18:54:04

标签: python linux eval sys

我有一个带有几个定义的python文件(以免称为pythonFile.py),所以我希望所有定义都可以用作使用该文件作为模块的python解释器和linux终端。 E.g:

def funct_1(arg1): #if arg1 is a string
    return arg1

def funct_2(arg1, arg2): #if both arg1 and arg2 are integers
    return arg1+arg2

def funct_3(arg1, arg2, arg3): #arg1 is str, arg2 is list, and arg3 is dict
    if (arg1 is str) and (arg2 is list) and (arg3 is dict):
        return 'It is Ok'
    else:
        return 'It is bad, very bad'

因此,在交互式解释器中使用此脚本可以正常工作:

>>> import pythonFile
>>> func_1('string here')
string here
>>> funct_2(2,4)
6
>>> funct_3(strVar, listVar, dictVar)
It is Ok

要在终端中使用它,我添加了以下代码(导入适当的模块):

if __name__ == "__main__":
    print eval(sys.argv[1])(*sys.argv[2:])

因此,eval(sys.argv[1])告诉我将使用哪个函数,(*sys.argv[2:])表示我放入的参数和数量。

这适用于funct_1,它只请求一个字符串:

$ python filePython.py funct_1 'print me'
print me

但不适用于funct_2fuct_3

$ python filePython.py func_2 6 4`
64
$ python filePython.py func_2 strVar listVar dictVar`
It is bad, very bad

显然,这是因为传递到终端的每个参数都被解析为string。一种解决方案是在定义中使用eval()。但是eval()是"邪恶",所以我更喜欢使用更安全的ast.literal_eval()

import sys
from ast import literal_eval as aeval 

def funct_1(arg1): #if arg1 is a string
    return arg1

def funct_2(arg1, arg2): #if both arg1 and arg2 are integers
    return int(arg1)+int(arg2)

def funct_3(arg1, arg2, arg3): #arg1 is str, arg2 is list, and arg3 is dict
    if (arg1 is str) and (aveal(arg2) is list) and (aeval(arg3) is dict):
        return 'It is Ok'
    else:
        return 'It is bad, very bad'

if __name__ == "__main__":
    print eval(sys.argv[1])(*sys.argv[2:]) # here I still using eval() instead aeval()

请注意,在funct_2我可以使用int()float()代替任何类型的eval()来解决问题。 现在,我可以使用终端中的funct_3

$ python filePython.py funct_3 strVar listVar dictVar
$ It is Ok

但不是来自python解释器:

>>> import pythonFile
>>> funct_3(strVar, listVar, dictVar)
It is bad, very bad

这是因为aeval()正在评估listdict而不是string。所以,我再次更改了我的代码,添加了一个新定义,将dictlist转换为str,稍后由aeval()进行评估(是的,我知道。是丑陋和愚蠢的,但到目前为止我知道的唯一方法。)

import sys
from ast import literal_eval as aeval

def strEval(var):
    return aeval(str(var))

def funct_1(arg1): #if arg1 is a string
    return arg1

def funct_2(arg1, arg2): #if both arg1 and arg2 are integers
    return int(arg1)+int(arg2)

def funct_3(arg1, arg2, arg3): #arg1 is str, arg2 is list, and arg3 is dict
    if (arg1 is str) and (strEval(arg2) is list) and (strEval(arg3) is dict):
        return 'It is Ok'
    else:
        return 'It is bad, very bad'

if __name__ == '__main__':
    print eval(sys.argv[1])(*sys.argv[2:])

现在,所有定义都适用于python解释器(作为模块)和linux终端(很棒!)。但我有两个问题:

  • 制作有用的方法是丑陋和缓慢的,因为我需要将对象类型列表,字典(和任何其他)转换为字符串,然后对其进行评估,将其再次返回到列表,字典等中。
  • 代码的最后一部分if __name__ == '__main__':仍然需要使用邪恶函数eval(),因为它不适用于ast.literal_eval()

这是我的两个问题。如果有人能帮助我解决这两个问题,我将非常感激。

1 个答案:

答案 0 :(得分:0)

此处无需使用eval()ast.literal_eval()(此处也不存在问题,因为您已经能够从命令行执行代码)。< / p>

Python允许您在命令行上使用表达式:

python -c "import filePython; filePython.funct_3('str', ['listVar'], {'dictVar': 'foo'})"

-c <command> switch与类固醇eval()类似,因为它接受完整的陈述,而不仅仅是表达式。试图避免eval()这里的问题根本不会产生任何差异因为任意代码执行已经发生。