преобразование sys.argv в (*args, **kwargs)
Как правильно преобразовать аргументы командной строки в (*args, **kwargs) с помощью sys.argv? Есть некоторая функция:
def test(*a, **b):
return print(a), print(b)
test('arg1', 'arg2', 'arg3', first='1', two='2', three='3')
Результат (все логично):
('arg1', 'arg2', 'arg3')
{'first': '1', 'two': '2', 'three': '3'}
Если попытаться передать те же аргументы через командную строку:
python3.8 code.py 'arg1', 'arg2', 'arg3', first='1', two='2', three='3'
и видоизменить саму функцию:
import sys
def test(*a, **b):
return print(a), print(b)
test(' '.join(sys.argv[1:]))
python3.8 args_.py 'arg1', 'arg2', 'arg3', first='1', two='2', three='3'
('arg1, arg2, arg3, first=1, two=2, three=3',)
{}
Ответы (1 шт):
Стандартного решения для такого варианта нет. Обычно используют различные библиотеки для разбора аргументов командной строки от стандартного argparse до click, например. Но там используется другой формат примерно такого вида:
python3 code.py arg1 arg2 arg3 --first=1 --two=2 --three=3
Обзор различных библиотек для разбора параметров командной строки можно почитать в этой статье: Сравнение популярных CLI-библиотек для Python: click, cement, fire и другие
Простое "наколеночное" решение для вашего формата:
import sys
import ast
def test(*args, **kwargs):
print(args)
print(kwargs)
print(sys.argv[1:])
args = []
kwargs = {}
for item in sys.argv[1:]:
item = item.rstrip(',')
if item: # Пустой элемент, например если была одиночная запятая
try:
args.append(ast.literal_eval(item))
except (ValueError, SyntaxError):
if "=" not in item:
args.append(item)
else:
key, value = item.split("=", maxsplit=1)
try:
kwargs[key] = ast.literal_eval(value)
except ValueError:
kwargs[key] = value
test(*args, **kwargs)
Вывод:
$ python3 test_args.py 'arg1', 'arg2', 'arg3', first='1', two=2, three='3'
['arg1,', 'arg2,', 'arg3,', 'first=1,', 'two=2,', 'three=3']
('arg1', 'arg2', 'arg3')
{'first': 1, 'two': 2, 'three': 3}
Все кавычки при при передаче через командную строку потерялись, поэтому числа в кавычках стали просто числами. Если нужно передавать именно строки, можно упростить код убрав попытки конвертации при помощи ast.literal_eval (все параметры будут считаться строками):
import sys
def test(*args, **kwargs):
print(args)
print(kwargs)
print(sys.argv[1:])
args = []
kwargs = {}
for item in sys.argv[1:]:
item = item.rstrip(',')
if item: # Пустой элемент, например если была одиночная запятая
if "=" not in item:
args.append(item)
else:
key, value = item.split("=", maxsplit=1)
kwargs[key] = value
test(*args, **kwargs)
Вывод будет такой:
$ python3 test_args.py 'arg1', 'arg2', 'arg3', first='1', two=2, three='3'
['arg1,', 'arg2,', 'arg3,', 'first=1,', 'two=2,', 'three=3']
('arg1', 'arg2', 'arg3')
{'first': '1', 'two': '2', 'three': '3'}