Verifique se o argumento opcional argparse está definido ou não


112

Gostaria de verificar se um argumento argparse opcional foi definido pelo usuário ou não.

Posso verificar com segurança usando o isset?

Algo assim:

if(isset(args.myArg)):
    #do something
else:
    #do something else

Isso funciona da mesma forma para argumentos do tipo float / int / string?

Eu poderia definir um parâmetro padrão e verificá-lo (por exemplo, definir myArg = -1, ou "" para uma string, ou "NOT_SET"). No entanto, o valor que desejo usar só é calculado posteriormente no script. Portanto, eu o configuraria como -1 como padrão e, em seguida, atualizaria para algo diferente. Isso parece um pouco desajeitado em comparação a simplesmente verificar se o valor foi definido pelo usuário.


1
O que isset()seria (dica: Python não é PHP)? Você quis dizer em hasattr()vez disso, talvez? Por que não configurar argparse para definir um padrão para uma opção?
Martijn Pieters

@MartijnPieters - sim, é verdade. Então, posso simplesmente verificar se (args.myArg): ...
Madeleine P. Vincent

Respostas:


146

Acho que os argumentos opcionais (especificados com --) são inicializados para Nonese não forem fornecidos. Então você pode testar com is not None. Experimente o exemplo abaixo:

import argparse as ap

def main():
    parser = ap.ArgumentParser(description="My Script")
    parser.add_argument("--myArg")
    args, leftovers = parser.parse_known_args()

    if args.myArg is not None:
        print "myArg has been set (value is %s)" % args.myArg

Os testes "é nenhum" e "não é nenhum" funcionam exatamente como eu gostaria e esperava. Obrigado.
Madeleine P. Vincent

39
Infelizmente não funciona, então o argumento tem seu defaultvalor definido.
kcpr

6
Se você deseja definir um default, ainda pode definir nargs='?'e fornecer um constvalor, conforme descrito nos documentos . Quando o arg está ausente, defaulté usado, quando arg dado o valor w / o, então consté usado, caso contrário, o valor fornecido é usado. Com apenas defaulte nargs='?', defaulté usado se não for fornecido, Nonese fornecido valor w / o, caso contrário, o valor fornecido.
Ioannis Filippidis

@IoannisFilippidis se você usar action= "store_true"ou action="store_const", const="yourconst"não puder usar esse argumento para armazenar outro valor. Isso não funcionará ao usar padrões. No meu próprio eu removi todos os padrões do argparser e lidei com todos dentro de outra função def defaults():onde eu misturo ConfigParser, ArgumentParser e valores padrão na ordem que eu quero
m3nda

@ erm3nda Não mencionei a configuração de um action. A resposta não usa um action. As ações que você menciona são documentadas para se comportarem de uma maneira específica (como você observou). Porém, não é necessário definir uma ação.
Ioannis Filippidis

37

Como observa @Honza, is Noneé um bom teste. É o padrão defaulte o usuário não pode fornecer uma string que o duplique.

Você pode especificar outro default='mydefaultvaluee testar isso. Mas e se o usuário especificar essa string? Isso conta como cenário ou não?

Você também pode especificar default=argparse.SUPPRESS. Então, se o usuário não usar o argumento, ele não aparecerá no argsnamespace. Mas testar isso pode ser mais complicado:

args.foo # raises an AttributeError
hasattr(args, 'foo')  # returns False
getattr(args, 'foo', 'other') # returns 'other'

Internamente, o parsermantém uma lista de seen_actionse a usa para testes 'obrigatórios' e 'mutuamente_exclusivos'. Mas não está disponível para você fora de parse_args.


22

Acho que usar a opção default=argparse.SUPPRESSfaz mais sentido. Então, em vez de verificar se o argumento é not None, verifica-se se o argumento éin o namespace resultante.

Exemplo:

import argparse

parser = argparse.ArgumentParser()
parser.add_argument("--foo", default=argparse.SUPPRESS)
ns = parser.parse_args()

print("Parsed arguments: {}".format(ns))
print("foo in namespace?: {}".format("foo" in ns))

Uso:

$ python argparse_test.py --foo 1
Parsed arguments: Namespace(foo='1')
foo in namespace?: True
O argumento não é fornecido:
$ python argparse_test.py
Parsed arguments: Namespace()
foo in namespace?: False

Isso não está funcionando para mim no Python 3.7.5 (Anaconda). Eu recebo o resultadotestfoo.py: error: argument --foo: expected one argument
Mike Wise

@MikeWise Se você quiser usar --foosem um valor (ou seja, 1no meu exemplo), você deve especificar nargs=0na add_argumentfunção.
Erasmus Cedernaes

Acabei de copiar e colar seu código conforme especificado na resposta. Talvez você deva editá-lo? Acabei usando a action='store_true'resposta abaixo no meu código real.
Mike Wise

@MikeWise você executou o script como python argparse_test.py --foo 1?
Erasmus Cedernaes

11

Você pode verificar uma bandeira opcionalmente passou com store_truee store_falseopções de ação argumento:

import argparse

argparser = argparse.ArgumentParser()
argparser.add_argument('-flag', dest='flag_exists', action='store_true')

print argparser.parse_args([])
# Namespace(flag_exists=False)
print argparser.parse_args(['-flag'])
# Namespace(flag_exists=True)

Dessa forma, você não precisa se preocupar em verificar por condicional is not None. Você simplesmente verifica Trueou False. Leia mais sobre essas opções nos documentos aqui


1
isso não resolve saber se um argumento que tem um valor está definido ou não. o principal problema aqui é saber se o valor args vem de defaul = "" ou é fornecido pelo usuário.
m3nda,

5

Se o seu argumento for posicional (ou seja, não tem um prefixo "-" ou "-", apenas o argumento, normalmente um nome de arquivo), você pode usar o parâmetro nargs para fazer isso:

parser = argparse.ArgumentParser(description='Foo is a program that does things')
parser.add_argument('filename', nargs='?')
args = parser.parse_args()

if args.filename is not None:
    print('The file name is {}'.format(args.filename))
else:
    print('Oh well ; No args, no problems')

3

Aqui está minha solução para ver se estou usando uma variável argparse

import argparse

ap = argparse.ArgumentParser()
ap.add_argument("-1", "--first", required=True)
ap.add_argument("-2", "--second", required=True)
ap.add_argument("-3", "--third", required=False) 
# Combine all arguments into a list called args
args = vars(ap.parse_args())
if args["third"] is not None:
# do something

Isso pode fornecer mais informações sobre a resposta acima, que usei e adaptei para trabalhar em meu programa.


0

Para responder ao comentário de @kcpr sobre a resposta (atualmente aceita) de @Honza Osobne

Infelizmente, não funciona, então o argumento tem seu valor padrão definido.

pode-se primeiro verificar se o argumento foi fornecido comparando-o com o Namespaceobjeto abd fornecendo a default=argparse.SUPPRESSopção (veja as respostas de @hpaulj e @Erasmus Cedernaes e este documento python3 ) e se não foi fornecido, defina-o com um valor padrão.

import argparse

parser = argparse.ArgumentParser()
parser.add_argument('--infile', default=argparse.SUPPRESS)
args = parser.parse_args()
if 'infile' in args: 
    # the argument is in the namespace, it's been provided by the user
    # set it to what has been provided
    theinfile = args.infile
    print('argument \'--infile\' was given, set to {}'.format(theinfile))
else:
    # the argument isn't in the namespace
    # set it to a default value
    theinfile = 'your_default.txt'
    print('argument \'--infile\' was not given, set to default {}'.format(theinfile))

Uso

$ python3 testargparse_so.py
argument '--infile' was not given, set to default your_default.txt

$ python3 testargparse_so.py --infile user_file.txt
argument '--infile' was given, set to user_file.txt

0

Muito simples, após definir a variável args por 'args = parser.parse_args ()', ela contém todos os dados das variáveis ​​do subconjunto args também. Para verificar se uma variável está definida ou não, assumindo que 'action = "store_true" é usado ...

if args.argument_name:
   # do something
else:
   # do something else
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.