В сочетании 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()
здесь просто не будет никакой разницы, поскольку выполнение произвольного кода уже должно произойти.