Verificar se sys.argv [x] está definido


Respostas:


64

No final, a diferença entre try, excepte o teste len(sys.argv)não é tão significativa. Ambos são um pouco hackeados em comparação com argparse.

Isso me ocorre, porém - como uma espécie de argumento de baixo orçamento:

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

Você pode até mesmo usá-lo para gerar um namedtuplecom valores padrão None- tudo em quatro linhas!

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

Caso você não esteja familiarizado namedtuple, é apenas uma tupla que atua como um objeto, permitindo que você acesse seus valores usando tup.attributesintaxe em vez de tup[0]sintaxe.

Portanto, a primeira linha cria um novo namedtupletipo com valores para cada um dos valores em arg_names. A segunda linha passa os valores do argsdicionário, usando getpara retornar um valor padrão quando o nome do argumento fornecido não tem um valor associado no dicionário.


Eu amo Python cada vez mais, tudo graças a respostas como essa e Stack Overflow, é claro! Pena que não temos uma explicação das duas últimas linhas. Eu acredito que para iniciantes isso seria ótimo.
— Goujon

2
Adoro! É facilmente a melhor solução que já vi para esse problema. Para outros: Não foi imediatamente óbvio para mim (newb) que: 1) o 'comando' passará como o primeiro argumento a cada vez e 2) você pode chamar os resultados com args [0] etc.
— Matt D

Isso é legal com certeza, mas o que há de errado em testar o comprimento?
— colorlace de

1
@timwiz eu estava falando apenas em comparação ao uso de argparse. Ainda assim, hoje em dia, eu me chuto toda vez que volto a um script antigo e descubro que não usei argparse.
— remetente em

116

Verifique o comprimento de sys.argv:

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

Algumas pessoas preferem a abordagem baseada em exceções que você sugeriu (por exemplo, try: blah = sys.argv[1]; except IndexError: blah = 'blah'), mas eu não gosto tanto porque ela não "escala" tão bem (por exemplo, quando você quer aceitar dois ou três argumentos) e pode potencialmente ocultar erros (por exemplo, se você usou blah = foo(sys.argv[1]), mas foo(...)levantou um IndexError, isso IndexErrorseria ignorado).


1
Enquanto você estiver sendo atômico sobre isso, não há nada com que se preocupar try, except. Apenas espere fooseu argumento até a elsecláusula.
— remetente

3
Além disso, quando você estiver pensando em dimensionar, é hora de passar para argparse.
— remetente em

1
+1 em argparse. Eu tenho argparse.pyem todos os meus projetos de linha de comando.
— David Wolever

2
@senderle: claro, se você for diligente sobre isso, tudo bem. Mas, na minha experiência, a maioria dos programadores não são diligentes e colocam toda a lógica na trycláusula ... Então, dado que não é mais difícil (e, IMO, um pouco mais bonito), prefiro apenas verificar o comprimento (também, você evita ter pessoas gritar com você por usar exceções para controle de fluxo).
— David Wolever

2
@David, sim, entendo seu ponto de vista. Sou um pouco tryapologista, devo admitir. Só sinto que às vezes expressa minha intenção com mais clareza do que uma ifdeclaração.
— remetente

22

Outra maneira que ainda não vi na lista é definir o valor de sentinela com antecedência. Este método tira proveito da avaliação preguiçosa do Python, na qual você nem sempre precisa fornecer uma elseinstrução. Exemplo:

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

Ou se você usar a sintaxe CRAZY, poderá usar o operador ternário do Python :

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

1
A resposta da operadora ternária é a meus olhos a mais bonita. Estou sentado aqui amaldiçoando silenciosamente o fato de que alguns dos softwares que mantenho estão vinculados ao Python 2.4, que não tem.
— Richard Barrell,

11

Eu uso isso - nunca falha:

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

Isso não é para verificar se definido. É mais como definir se existe, o que não é o mesmo. Usei essa forma também para avaliar variáveis ​​de fallback, mas não é uma resposta à pergunta atual.
— m3nda

@ erm3nda Posso remover a startingpointvariável do exemplo, mas a questão é atribuir uma variável de fallback, então acabei de fazer o mesmo.
— anatoly techtonik

1
Se você removê-lo, obterá um erro sobre a variável não definida. Li novamente a pergunta, e o que ele espera é uma substituição de variável :) então está tudo bem. Obrigado pelo conselho desse caminho curto se sys.argv[1:]:. Isso funciona com argumentos posicionais, enquanto a contagem não.
— m3nda de

10

É uma lista comum do Python. A exceção que você capturaria para isso é IndexError, mas é melhor verificar apenas o comprimento.

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

2

Uma solução que trabalha com função de mapa embutido!

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

Então você só precisa chamar seus parâmetros desta forma:

if args['operation'] == "division":
    if not args['parameter']:
        ...
    if args['parameter'] == "euclidian":
        ...

1

Você pode simplesmente anexar o valor de argv [1] a argv e, em seguida, verificar se argv [1] não é igual à string inserida. Exemplo:

from sys import argv
argv.append('SomeString')
if argv[1]!="SomeString":
            print(argv[1])

para quem votou contra mim, que vergonha, por não esclarecer o erro.
— Hassan Abdul-Kareem

Acho que é porque é hackeado. E se alguém passar SomeString como um argumento? Como usar isso se você pode aceitar, digamos, 1 a 5 argumentos?
— pbogut

Legal (mas ainda hackish) para definir um valor padrão caso o usuário não forneça o argumento. Basta anexar e usar argv [1].
— Felizett

1

Muito perto do que o criador estava tentando fazer. Aqui está uma função que uso:

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

Portanto, um uso seria algo como:

if __name__ == "__main__":
    banner(get_arg(1),get_arg(2))
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.