Передача списка в Python из командной строки - PullRequest
26 голосов
/ 30 сентября 2011

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

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

Ответы [ 4 ]

28 голосов
/ 30 сентября 2011

Программа:

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.

26 голосов
/ 30 сентября 2011

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()

или похожие.Используйте аргумент с split для разделения вашего списка:

% 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']

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

4 голосов
/ 30 сентября 2011

Да, 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'"])
0 голосов
/ 06 января 2014

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

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

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

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

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

...