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.

remetente
fonte
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).

David Wolever
fonte
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'
jatanismo
fonte
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]
anatoly techtonik
fonte
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'
Richard Barrell
fonte
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":
        ...
Guillaume Hillion
fonte
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])
Hassan Abdul-Kareem
fonte
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))
J. Barber
fonte