Перевірка, чи визначено sys.argv [x]


Відповіді:


64

Зрештою, різниця між try, exceptі тестуванням len(sys.argv)не все така істотна. Вони обидва трохи хакітні порівняно з 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, все завдяки таким відповідям і звичайно переповненню стека! Шкода, що ми не маємо пояснення останніх двох рядків. Я вважаю, для початківців це було б чудово.
Гуджон

2
Любіть це! Легко найкраще рішення цієї проблеми. Для інших: мені не відразу було очевидно (newb), що: 1) команда буде передаватися як перший аргумент кожного разу, і 2) ви можете викликати результати за допомогою аргументів [0] тощо.
Matt D

Це круто напевно, але що хакі в тестуванні довжини?
colorlace

1
@timwiz Я говорив лише порівняно з використанням argparse. І все-таки в ці дні я відбиваю себе щоразу, коли повертаюся до старого сценарію і виявляю, що не використовував аргументацію.
senderle

116

Перевірте довжину 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застереження.
відправник

3
Крім того, як тільки ви думаєте про масштабування, саме час перейти до argparse.
відправник

1
+1 за аргументацією. У мене є argparse.pyвсі мої проекти командного рядка.
Девід Волвер

2
@senderle: впевнено, якщо ви старанно ставитесь до цього, це добре. Але, на мій досвід, більшість програмістів не старанні і вкладають всю логіку в tryпункт ... Отже, враховуючи, що це не важче (і, IMO, трохи гарніше), я вважаю за краще просто перевірити довжину (також, ви не хочете мати людей кричатимете на те, що використовуєте винятки для контролю потоку).
Девід Волвер

2
@David, так, я бачу вашу думку. Я трохи tryапологет, мушу визнати. Я просто відчуваю, що іноді це виражає мій намір чіткіше, ніж ifтвердження.
відправник

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, в якому його немає.
Річард Баррелл

11

Я використовую це - це ніколи не виходить з ладу:

startingpoint = 'blah'
if sys.argv[1:]:
   startingpoint = sys.argv[1]

Це не для перевірки, якщо визначено. Більше схоже на визначення, якщо існує, що не те саме. Я також використовував цей спосіб для отримання резервних змінних, але це не відповідь на поточне запитання.
м3нда

@ erm3nda Я можу видалити startingpointзмінну з прикладу, але питання про призначення резервної змінної, тому я просто зробив те саме.
anatoly techtonik

1
Якщо ви видалите його, ви отримаєте помилку щодо змінної, яка не визначена. Я ще раз прочитав питання, і чого він очікує, що це заміна змінної :) так що це нормально. Дякуємо вам за пораду, що такий короткий шлях sys.argv[1:]:. Це працює з позиційними аргументами, а підрахунок - ні.
м3нда

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 аргументів?
pbogut

Класно (але все одно хакі) для встановлення значення за замовчуванням у випадку, якщо користувач не подає аргумент. Просто додайте та використовуйте 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))
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.