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

Я пишу приложение, которое принимает произвольные аргументы командной строки, а затем передает их в функцию Python:

$ myscript.py --arg1=1 --arg2=foobar --arg1=4

а затем внутри myscript.py:

import sys
argsdict = some_function(sys.argv)

где argsdict выглядит так:

{'arg1': ['1', '4'], 'arg2': 'foobar'}

Я уверен, что где-то есть библиотека, которая делает это, но я ничего не могу найти.

EDIT: argparse/getopt/optparse — это не то, что мне нужно. Эти библиотеки предназначены для определения интерфейса, который будет одинаковым для каждого вызова. Мне нужно иметь возможность обрабатывать произвольные аргументы.

Если argparse/optparse/getopt не имеет функций, которые делают это...


person priestc    schedule 09.10.2012    source источник
comment
docs.python.org/dev/library/argparse.html   -  person John Vinyard    schedule 10.10.2012
comment
argparse совершенно другой, он предназначен для определения интерфейса командной строки. Я пытаюсь разобрать произвольный интерфейс командной строки. Каждый вызов этого скрипта каждый раз будет иметь разные аргументы.   -  person priestc    schedule 10.10.2012
comment
Я думаю, что это все еще возможно сделать с помощью argparse. Если вы не хотите его использовать, то, насколько мне известно, у вас нет другого выбора, кроме как написать парсер для аргументов самостоятельно.   -  person Andrew Gorcester    schedule 10.10.2012
comment
Да, я также не могу понять, как анализировать произвольные аргументы с помощью стандартных библиотек...   -  person bumpkin    schedule 23.10.2014
comment
Это все еще не раскрыто спустя 5 лет? Мне нужно это писать??   -  person prismofeverything    schedule 12.06.2019


Ответы (7)


Вот пример использования argparse, хотя это и натянуто. Я бы не назвал это полным решением, скорее хорошим началом.

class StoreInDict(argparse.Action):
    def __call__(self, parser, namespace, values, option_string=None):
        d = getattr(namespace, self.dest)
        for opt in values:
            k,v = opt.split("=", 1)
            k = k.lstrip("-")
            if k in d:
                d[k].append(v)
            else:
                d[k] = [v]
        setattr(namespace, self.dest, d)

# Prevent argparse from trying to distinguish between positional arguments
# and optional arguments. Yes, it's a hack.
p = argparse.ArgumentParser( prefix_chars=' ' )

# Put all arguments in a single list, and process them with the custom action above,
# which convertes each "--key=value" argument to a "(key,value)" tuple and then
# merges it into the given dictionary.
p.add_argument("options", nargs="*", action=StoreInDict, default=dict())

args = p.parse_args("--arg1=1 --arg2=foo --arg1=4".split())
print args.options
person chepner    schedule 13.10.2012

Вы можете использовать что-то вроде этого:

myscript.py

import sys
from collections import defaultdict

d=defaultdict(list)
for k, v in ((k.lstrip('-'), v) for k,v in (a.split('=') for a in sys.argv[1:])):
    d[k].append(v)

print dict(d)

Результат:

C:\>python myscript.py  --arg1=1 --arg2=foobar --arg1=4
{'arg1': ['1', '4'], 'arg2': ['foobar']}

Примечание: значение всегда будет списком, но я думаю, что это более последовательно. Если вы действительно хотите, чтобы окончательный словарь был

{'arg1': ['1', '4'], 'arg2': 'foobar'}

тогда вы могли бы просто бежать

for k in (k for k in d if len(d[k])==1):
    d[k] = d[k][0]

после.

person sloth    schedule 09.10.2012

Что-то вроде этого?

import sys

argsdict = {}

for farg in sys.argv:
    if farg.startswith('--'):
        (arg,val) = farg.split("=")
        arg = arg[2:]

        if arg in argsdict:
            argsdict[arg].append(val)
        else:
            argsdict[arg] = [val]     

Немного отличающееся от указанного значение всегда представляет собой список.

person cdarke    schedule 09.10.2012
comment
Я рекомендую использовать defaultdict для вашей переменной argsdict. Таким образом, вы избавляетесь от теста in и можете добавлять, не беспокоясь. Это делает ваш код более кратким и выразительным и, следовательно, питоническим. - person halex; 10.10.2012

..могу спросить, почему вы пытаетесь переписать (кучу) колес, когда у вас есть:

?

РЕДАКТИРОВАТЬ:

В ответ на ваше редактирование optparse/argparse (последний доступен только в >= 2.7) достаточно гибок, чтобы расширяться в соответствии с вашими потребностями, сохраняя при этом согласованный интерфейс (например, пользователь ожидает, что сможет использовать как --arg=value, так и --arg value , -a value и -avalue и т. д., используя уже существующую библиотеку, вам не нужно беспокоиться о поддержке всех этих синтаксисов и т. д.).

person redShadow    schedule 09.10.2012
comment
как бы вы расширили argparse, например, для разбора произвольных аргументов? не могу понять это. - person bumpkin; 23.10.2014

Это то, что я использовал сегодня, это составляет:

--key=val, --key, -key, -key val

def clean_arguments(args):
    ret_args = defaultdict(list)

    for index, k in enumerate(args):
        if index < len(args) - 1:
            a, b = k, args[index+1]
        else:
            a, b = k, None

        new_key = None

        # double hyphen, equals
        if a.startswith('--') and '=' in a:
            new_key, val = a.split('=')

        # double hyphen, no equals
        # single hyphen, no arg
        elif (a.startswith('--') and '=' not in a) or \
                (a.startswith('-') and (not b or b.startswith('-'))):
            val = True

        # single hypen, arg
        elif a.startswith('-') and b and not b.startswith('-'):
            val = b

        else:
            if (b is None) or (a == val):
                continue

            else:
                raise ValueError('Unexpected argument pair: %s, %s' % (a, b))

        # santize the key
        key = (new_key or a).strip(' -')
        ret_args[key].append(val)

    return ret_args
person blakev    schedule 04.12.2015

Или как-то так) Извините, если глупо, я новичок :)

$ python3 Test.py а 1 б 2 в 3

import sys

def somefunc():
    keys = []
    values = []
    input_d = sys.argv[1:]

    for i in range(0, len(input_d)-1, 2):
        keys.append(input_d[i])
        values.append(input_d[i+1])

    d_sys = dict(zip(keys, values))

somefunc()
person Roma Bondarenko    schedule 01.10.2018

Если вы действительно хотите написать что-то свое вместо правильной библиотеки синтаксического анализа командной строки, для вашего ввода это должно работать:

dict(map(lambda x: x.lstrip('-').split('='),sys.argv[1:]))

Вы захотите добавить что-нибудь для перехвата аргументов без знака «=» в них.

person John Fink    schedule 09.10.2012
comment
Это не даст желаемых результатов. Используя пример OP, arg1 не будет отображаться на 1 и 4, а только на 4. - person sloth; 10.10.2012