Как передать словарь в качестве аргумента командной строки для python script?

Как передать словарь в качестве аргумента командной строки для python script? Мне нужно получить словарь, где ключ - строка, а значение - список некоторых элементов (например, чтобы выглядеть следующим образом:

command_line_arguments = {"names" : ["J.J.", "April"], "years" : [25, 29]}

Я пробовал как

if __name__ == '__main__':
    args = dict([arg.split('=') for arg in sys.argv[2:]]) # also tried with 1 but doesn't work
    main(args)

и я вызываю script как

$ python saver.py names=["J.J.", "April"] years=[25, 29]

но он не работает, словарь имеет длину 0 и нужен 2. Может ли кто-нибудь помочь мне передать и создать словарь в основном.

Ответы

Ответ 1

Здесь важно отметить, что в командной строке нельзя передавать объекты Python в качестве аргументов. Текущая оболочка, которую вы используете, будет анализировать аргументы и передавать их в соответствии со своими собственными правилами разбора аргументов.

При этом, вы не можете перейти в словарь Python. Тем не менее, такие вещи, как JSON, могут позволить вам быть очень близкими.

Представление объектов в формате JSON или JavaScript - это способ получения объектов Python и их преобразования в строковое представление, подходящее для передачи на несколько языков. При этом, вы можете передать в строку, как это:

python saver.py '{"names": ["J.J.", "April"], "years": [25, 29]}'

В вашем скрипте Python сделайте это:

import json
data=json.loads(argv[1])

Это вернет вам словарь, представляющий данные, которые вы хотели передать.

Кроме того, вы можете взять словарь Python и преобразовать его в строку:

import json
data={'names': ["J.J.", "April"], 'years': [25,29]}
data_str=json.dumps(data)

Есть и другие способы достижения этого, хотя JSON довольно универсален. Главное, на что нужно обратить внимание: независимо от того, как вы это сделаете - вы не будете передавать словарь в Python, - вы будете передавать набор аргументов (которые будут строками), которые вам как-то понадобятся преобразовать в нужный вам тип питона.

@EvanZamir - обратите внимание, что (как правило) в оболочке вам нужно избегать кавычек, если они появляются в вашей строке в кавычках. В моем примере я цитирую данные JSON одинарными кавычками, а сама строка json использует двойные кавычки, тем самым устраняя необходимость в кавычках.

Если вы смешиваете кавычки (используйте двойные кавычки для кавычек аргумента и двойные кавычки внутри), то оболочка потребует экранирования, в противном случае первая двойная кавычка, с которой она сталкивается, считается "закрывающей кавычкой" для аргумента. Обратите внимание, что в примере я использую одинарные кавычки для заключения строки JSON и двойные кавычки в строке. Если бы я использовал одинарные кавычки в строке, мне нужно было бы экранировать их, используя обратную косую черту, то есть:

python saver.py '{"names": ["J.J.", "April\'s"], "years": [25, 29]}'

или же

python saver.py "{\"names\": [\"J.J.\", \"April's\"], \"years\": [25, 29]}"

Обратите внимание, что цитирование - это функция вашей оболочки, поэтому YMMV может отличаться (например, если вы используете какой-либо метод exec для вызова сценария, экранирование может не потребоваться, поскольку оболочка bash может не вызываться.)

Ответ 2

Вот еще один метод с использованием стандартного ввода. Это метод, который вы хотите использовать для интерфейса json cgi (то есть веб-сервер передает запрос в ваш скрипт):

Python:

 import json, sys
 request = json.load( sys.stdin )
...

Чтобы проверить ваш скрипт из терминала Linux:

echo '{ "key1": "value 1", "key2": "value 2" }' | python myscript.py

Чтобы проверить ваш скрипт из терминала Windows:

echo { "key1": "value 1", "key2": "value 2" } | python myscript.py

Ответ 3

Проверьте это:

>>> from sys import argv
>>> from re import findall
>>> args = ' '.join(argv[1:])
>>> pattern = r'([^=]+)\s*=\s*\[\s*([^\]]+)\s*\]'
>>> d = dict((t[0].strip(), map(lambda x: x.strip(', '),t[1].split())) for t in findall(pattern,args))
>>> for k,v in d.items():
    try: d[k] = map(int,v)
    except: pass    
>>> d
{'names': ['"J.J."', '"April"'], 'years': [25, 29]}

Ответ 4

Я начал с отличного ответа @chander, но столкнулся с проблемами, связанными с экранированием специальных символов, как на уровне оболочки/команды, так и внутри скрипта python. Сохранение JSON в файл и последующая передача этого имени файла в качестве параметра в сценарий будет возможным решением, но в моей ситуации это будет довольно сложно.

Поэтому вместо этого я решил url-кодировать строку на уровне аргумента и декодировать ее внутри скрипта Python. Это означает, что все, что вызывает скрипт python, должно кодировать URL-адрес аргумента командной строки, который является строкой JSON. Существует множество онлайн-инструментов, которые позволяют создавать песочницу с URL-кодированием строки. В моем случае скрипт nodejs вызывает вызов скрипта python и может легко кодировать URL JSON.

Внутри скрипта Python это выглядит так (вам не нужно использовать argparse, но мне это нравится):

import json
import argparse
from urllib.parse import unquote

# Set up CLI Arguments
parser = argparse.ArgumentParser()

# Required Arguments
parser.add_argument("-c", "--config", required=True,
                    help="JSON configuration string for this operation")

# Grab the Arguments
args = parser.parse_args()

jsonString = unquote(args.config)

print(jsonString)

config = json.loads(jsonString)

print(config)