Проверка, определен ли sys.argv [x]

Ответы:

64

В конце концов, разница между try, exceptтестированием len(sys.argv)и не так уж и значительна. Они оба немного хакерские по сравнению с argparse.

Однако это приходит мне в голову - как своего рода малобюджетный argparse:

arg_names = ['command', 'x', 'y', 'operation', 'option']
args = dict(zip(arg_names, sys.argv))

Вы даже можете использовать его для генерации namedtupleсо значениями по умолчанию None- всего в четырех строках!

Arg_list = collections.namedtuple('Arg_list', arg_names)
args = Arg_list(*(args.get(arg, None) for arg in arg_names))

Если вы не знакомы с этим namedtuple, это просто кортеж, который действует как объект, позволяя вам получить доступ к его значениям, используя tup.attributeсинтаксис вместо tup[0]синтаксиса.

Итак, первая строка создает новый namedtupleтип со значениями для каждого из значений в arg_names. Вторая строка передает значения из argsсловаря, используя getдля возврата значения по умолчанию, когда данное имя аргумента не имеет связанного значения в словаре.

отправитель
источник
Я люблю Python все больше и больше, все благодаря таким ответам и, конечно же, Stack Overflow! Жаль, что у нас нет объяснения последних двух строк. Я считаю, что для новичков это было бы здорово.
Goujon
2
Любить это! Лучшее решение этой проблемы, которое я видел. Для других: для меня не сразу было очевидно (newb), что: 1) 'команда' будет каждый раз проходить как первый аргумент и 2) вы можете вызывать результаты с помощью args [0] и т. Д.
Мэтт Д.
Это конечно круто, но что за хакерство в тестировании длины?
colorlace
1
@timwiz Я говорил только по сравнению с использованием argparse. Тем не менее, в наши дни я бью себя каждый раз, когда возвращаюсь к старому скрипту и обнаруживаю, что не использовал argparse.
senderle 09
117

Проверьте длину sys.argv:

if len(sys.argv) > 1:
    blah = sys.argv[1]
else:
    blah = 'blah'

Некоторые люди предпочитают подход, основанный на исключениях, который вы предложили (например, try: blah = sys.argv[1]; except IndexError: blah = 'blah'), но мне он не нравится, потому что он не так хорошо «масштабируется» (например, когда вы хотите принять два или три аргумента) и он потенциально может скрыть ошибки (например, если вы использовали blah = foo(sys.argv[1]), но foo(...)подняли IndexError, это IndexErrorбудет проигнорировано).

Дэвид Волевер
источник
1
Но пока вы относитесь к этому атомарно, вам не о чем беспокоиться try, except. Просто дождитесь fooсвоего аргумента до elseпункта.
senderle
3
Кроме того, если вы задумались о масштабировании, пора переходить к argparse.
senderle
1
+1 на argparse. У меня есть argparse.pyвсе мои проекты командной строки.
Дэвид Волевер
2
@senderle: конечно, если вы прилежны, ничего страшного. Но по моему опыту, большинство программистов не усердны и не вкладывают всю логику в tryпредложение ... Итак, учитывая, что это не сложнее (и, IMO, немного красивее), я предпочитаю просто проверять длину (кроме того, вы избегаете того, чтобы люди кричать на вас за использование исключений для управления потоком).
Дэвид Волевер
2
@ Дэвид, да, я понимаю твою точку зрения. tryДолжен признать, я немного извиняюсь. Я просто чувствую, что иногда это выражает мои намерения более ясно, чем ifзаявление.
senderle
22

Еще один способ, который я еще не видел в списке, - это заранее установить контрольное значение. Этот метод использует преимущества отложенного вычисления Python, при котором вам не всегда нужно предоставлять elseоператор. Пример:

startingpoint = 'blah'
if len(sys.argv) >= 2:
  startingpoint = sys.argv[1]

Или, если вы используете синтаксис CRAZY, вы можете использовать тернарный оператор Python :

startingpoint = sys.argv[1] if len(sys.argv) >= 2 else 'blah'
джатанизм
источник
1
Ответ тернарного оператора на мой взгляд самый красивый. Я сижу здесь и тихо проклинаю тот факт, что часть поддерживаемого мной программного обеспечения привязано к Python 2.4, на котором его нет.
Ричард Баррелл,
12

Я использую это - никогда не подводит:

startingpoint = 'blah'
if sys.argv[1:]:
   startingpoint = sys.argv[1]
анатолий техтоник
источник
Это не для проверки, если определено. Это больше похоже на определение, если существует, что не то же самое. Я тоже использовал этот способ для задания резервных переменных, но это не ответ на текущий вопрос.
m3nda,
@ erm3nda Я могу удалить startingpointпеременную из примера, но вопрос заключается в назначении резервной переменной, поэтому я сделал то же самое.
анатолий техтоник
1
Если вы удалите его, вы получите ошибку о том, что переменная не определена. Я снова прочитал вопрос, и он ожидает, что это замена переменной :), так что все в порядке. Спасибо за совет о таком коротком пути if sys.argv[1:]:. Это работает с позиционными аргументами, а count - нет.
m3nda
10

Это обычный список Python. Исключением, которое вы могли бы поймать для этого, является IndexError, но вместо этого вам лучше просто проверить длину.

if len(sys.argv) >= 2:
  startingpoint = sys.argv[1]
else:
  startingpoint = 'blah'
Ричард Баррелл
источник
2

Решение, работающее со встроенной функцией карты!

arg_names = ['command' ,'operation', 'parameter']
args = map(None, arg_names, sys.argv)
args = {k:v for (k,v) in args}

Тогда вам просто нужно вызвать свои параметры следующим образом:

if args['operation'] == "division":
    if not args['parameter']:
        ...
    if args['parameter'] == "euclidian":
        ...
Гийом Хиллион
источник
1

Вы можете просто добавить значение argv [1] к argv, а затем проверить, не совпадает ли argv [1] с введенной вами строкой. Пример:

from sys import argv
argv.append('SomeString')
if argv[1]!="SomeString":
            print(argv[1])
Хасан Абдул-Карим
источник
для тех, кто проголосовал против меня, позор вам, за то, что не разъяснили ошибку.
Хасан Абдул-Карим
Думаю, это потому, что это хакерское занятие. Что, если кто-то передаст SomeString в качестве аргумента? Как это использовать, если вы можете принять, скажем, от 1 до 5 аргументов?
пбогут
Круто (но все же хакерское) для установки значения по умолчанию в случае, если пользователь не предоставляет аргумент. Просто добавьте, а затем используйте argv [1].
Felizett
1

Довольно близко к тому, что пытался сделать создатель. Вот функция, которую я использую:

def get_arg(index):
    try:
        sys.argv[index]
    except IndexError:
        return ''
    else:
        return sys.argv[index]

Таким образом, использование будет примерно таким:

if __name__ == "__main__":
    banner(get_arg(1),get_arg(2))
Дж. Барбер
источник