Подтвердить что ты не робот

Передача списка в Python из командной строки

Я хочу, чтобы мой python script запускался из командной строки при поставках с некоторыми аргументами. Однако одним из аргументов должен быть список опций, относящихся к одному сегменту script. Будет ли синтаксический анализ единственным способом сделать это, фактически создав список после того, как строка "строка командной строки" будет разделена на запятую? Если да, как бы вы это сделали?

Пример: -details = ['name', 'title', 'address']

4b9b3361

Ответ 1

Программа:

import sys, ast, getopt, types

def main(argv):            
    arg_dict={}
    switches={'li':list,'di':dict,'tu':tuple}
    singles=''.join([x[0]+':' for x in switches])
    long_form=[x+'=' for x in switches]
    d={x[0]+':':'--'+x for x in switches}
    try:            
        opts, args = getopt.getopt(argv, singles, long_form)
    except getopt.GetoptError:          
        print "bad arg"                       
        sys.exit(2)       

    for opt, arg in opts:        
        if opt[1]+':' in d: o=d[opt[1]+':'][2:]
        elif opt in d.values(): o=opt[2:]
        else: o =''
        print opt, arg,o
        if o and arg:
            arg_dict[o]=ast.literal_eval(arg)

        if not o or not isinstance(arg_dict[o], switches[o]):    
            print opt, arg, " Error: bad arg"
            sys.exit(2)                 

    for e in arg_dict:
        print e, arg_dict[e], type(arg_dict[e])        

if __name__ == '__main__':
    main(sys.argv[1:])        

Командная строка:

python py.py --l='[1,2,3,[1,2,3]]' -d "{1:'one',2:'two',3:'three'}" --tu='(1,2,3)'

Вывод:

args:  ['--l=[1,2,3,[1,2,3]]', '-d', "{1:'one',2:'two',3:'three'}", '--tu=(1,2,3)']
tu (1, 2, 3) <type 'tuple'>
di {1: 'one', 2: 'two', 3: 'three'} <type 'dict'>
li [1, 2, 3, [1, 2, 3]] <type 'list'>

Этот фрагмент кода будет содержать короткие или длинные командные переключатели, такие как -l или --li=, и проанализировать текст после переключения в структуру данных Python, такую ​​как список, кортеж или dict. Анализируемая структура данных заканчивается в словаре с ключом с длинным ключом.

Использование ast.literal_eval относительно безопасно. Он может анализировать только определения данных python.

Ответ 2

argparse хорош для этого, он в стандартной библиотеке с 2,7 и 3,2, но в остальном pip install прочь.

Ваша основная проблема при указании списка переменной длины может быть решена путем преобразования списка в один аргумент в оболочке с помощью кавычек (может быть, зависит от вашей оболочки, я полагаю):

% python prog.py 'name title address' spam

где prog.py содержит

import sys
my_list = sys.argv[1].split() 
# my_list is ['name', 'title', 'address']
if 'name' in my_list:
   do_something()

или аналогичный. Используйте аргумент с разделом, чтобы разграничить список:

% python prog.py "you're a foo, lift the bar"

my_list = [x.strip() for x in  sys.argv[1].split(',')]
# my_list is ["you're a foo", "lift the bar"]

Но вместо этого используйте argparse; особенно если вы хотите использовать флаги стиля -c.

Один из способов интерпретировать ваш вопрос:

"Я уже использую argparse, так как это разумный способ интерпретировать аргументы командной строки в Python. Как указать, что некоторые параметры находятся в определенной категории?"

В вашем вопросе вы показали пример того, что оболочки, которые я использую, задохнутся;

% python prog.py -v -details=['name', 'title', 'address'] --quickly -t 4

не будет обрабатывать python, потому что они будут использовать пробелы для разделения аргументов и могут использовать [и] как синтаксис оболочки.

Я предлагаю вместо этого

% python prog.py -v --details name title address --quickly -t 4

где файл prog.py

import argparse

parser = argparse.ArgumentParser() 
parser.add_argument('-v', action='store_true')
parser.add_argument('--details', nargs='*')
parser.add_argument('--quickly', action='store_true')
parser.add_argument('-t')

args = parser.parse_args()
#args is Namespace(details=['asdf', 'a', 'a'], quickly=False, t='4', v=True)
details = args.details
#details is ['asdf', 'a', 'a']

Теперь, согласно вашему вопросу, вам не нужно было выполнять синтаксический анализ.

Ответ 3

Да, argparse - ваш лучший выбор, и если вы хотите предоставить список значений одному из ваших именованных аргументов, (параметр nargs является ключом к этому):

>>> import argparse
>>> arg_parser = argparse.ArgumentParser()
>>> arg_parser.add_argument('--details',
                            nargs='*',
                            type=str,
                            default=[],
                            help='a list of the details')

# your args on the command line like this example
>>> the_args = arg_parser.parse_args("--details 'name' 'title' 'address'".split())
>>> print the_args.details
["'name'", "'title'", "'address'"])

Ответ 4

Мне очень нравится the-wolf, используя коллекции переменной длины как явные строковые аргументы.

По-моему, nargs='*' имеет примечательные недостатки: при попытке собрать строки в качестве позиционных аргументов (хотя бы одна строка должна присутствовать), или если вы пытаетесь использовать подпарамеры, вы обнаружите, что nargs='*' и nargs='+' используйте жадное завершение, и они, похоже, не перестают потреблять по каким-либо веским причинам. Даже если появляется синтаксис для необязательного аргумента или числа, тип string() будет продолжать потреблять. (Это становится сложнее предвидеть с помощью подпараметров).

Лучший случай, аргументы, помещенные после (позиционный и необязательный), игнорируются, и, что еще хуже, вы, скорее всего, передаете коррумпированные типы данных в массив argparse.

Мы должны иметь возможность определить пользовательский ActionType, который ищет строку с кавычками. Если он найдет один, то мы адаптируем the-wolf примеры (почти дословно).

Это сохраняет чистоту в argparse и делает использование переменных коллекций гораздо менее суровым.