В сочетании ast.literal_eval и sys.argv

У меня есть файл Python (чтобы не называется pythonFile.py) с несколькими определениями, поэтому я хочу, чтобы все определения могли использоваться как интерпретатором python, использующим файл в качестве модуля, так и терминалом linux. Например:

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_2 а также fuct_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() сейчас оценивает list а также dict вместо string, Итак, снова я изменяю свой код, добавляя новое определение, которое превращает любой dict а также list в 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 (отлично!). Но у меня есть две проблемы:

  • Способ сделать полезным уродлив и медленен, потому что мне нужно преобразовать список типов объектов, dict (и любой другой) в строку, а затем оценить его, вернуть его снова в list, dict и т. Д.
  • Последняя часть кода if __name__ == '__main__': нужно еще использовать злую функцию eval() потому что это не работает с ast.literal_eval(),

Это две мои проблемы. Если кто-то может помочь мне решить эти два вопроса, я буду очень благодарен.

1 ответ

Там нет необходимости использовать eval() или же ast.literal_eval() здесь (и это не проблема здесь, так как вы уже можете выполнять код из командной строки).

Python позволяет использовать выражения в командной строке:

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

-c <command> переключатель как eval() на стероидах, поскольку он принимает полные утверждения, а не только выражения. Пытаясь избежать проблем eval() здесь просто не будет никакой разницы, поскольку выполнение произвольного кода уже должно произойти.

Другие вопросы по тегам