Executar função a partir da linha de comando

363

Eu tenho este código:

def hello():
    return 'Hi :)'

Como eu executaria isso diretamente na linha de comando?

Steven
fonte
21
Provavelmente você quis dizer em print "Hi :)"vez de return 'Hi :)'.
Tamás

Respostas:

567

Com o argumento -c (command) (assumindo que seu arquivo tenha o nome foo.py):

$ python -c 'import foo; print foo.hello()'

Como alternativa, se você não se importa com a poluição do espaço para nome:

$ python -c 'from foo import *; print hello()'

E o meio termo:

$ python -c 'from foo import hello; print hello()'
Frédéric Hamidi
fonte
32
Observei que, no shell do Windows, você precisa de aspas duplas em vez de simples. $python -c "import foo;foo.hello()"
Arindam Roychowdhury
6
E se o arquivo não estiver no diretório local ou no PYTHONPATH?
Konstantin
2
O segundo é uma resposta mais geral. Eu tenho um script definido várias funções do cliente, e só chamar um dependendo de minha necessidade
xappppp
11
Por alguma razão, isso não funcionou para mim, enquanto a substituição print foo.hello()por print(foo.hello())funcionou. Eu não tenho o conhecimento de python para explicar por que isso ocorre; portanto, se alguém puder explicar o que pode estar acontecendo, isso seria muito apreciado.
Jasper
2
@Aakanksha Obrigado pela explicação, e isso definitivamente faz sentido. Parece correto editar a resposta para incluir os parênteses? Isso o tornaria compatível com o python 2 e 3 se não me engano. (Em momentos como esse, eu gostaria de poder fazer uma sugestão de edição.)
Jasper
130

Basta colocar em hello()algum lugar abaixo da função e ela será executada quando você fizerpython your_file.py

Para uma solução mais limpa, você pode usar o seguinte:

if __name__ == '__main__':
    hello()

Dessa forma, a função somente será executada se você executar o arquivo, não quando importar o arquivo.

Wolph
fonte
3
E se hello()receber argumentos que devem ser fornecidos pela linha de comando?
Anônimo
2
Nesse caso, você pode enviar sys.argvpara o método Ou acessá-lo a partir do método Olá
Wolph
3
Uma diferença entre essa resposta e a solução import foo é que o import foo permite chamar uma função arbitrária no foo sem modificá-lo.
plafratt
Isso é verdade, mas eu não recomendaria essa solução além fins de teste
Wolph
@Wolph Ei, com essa estrutura, como executo uma função separada (não incluída dentro hello()) e a executo a partir da linha de comando?
Souvik Ray
66

python -c 'from myfile import hello; hello()'onde myfiledeve ser substituído pelo nome de base do seu script Python. (Por exemplo, myfile.pytorna-se myfile).

No entanto, se hello()é o seu ponto de entrada principal "permanente" no seu script Python, a maneira usual de fazer isso é a seguinte:

def hello():
    print "Hi :)"

if __name__ == "__main__":
    hello()

Isso permite que você execute o script simplesmente executando python myfile.pyou python -m myfile.

Alguma explicação aqui: __name__é uma variável Python especial que contém o nome do módulo que está sendo executado atualmente, exceto quando o módulo é iniciado a partir da linha de comando; nesse caso, ele se torna "__main__".

Tamás
fonte
2
Qual é a diferença entre python -m foo -c 'foo.bar()'e python -c 'import foo; foo.bar()'? Recebo um comportamento diferente, onde parece que o argumento -c é ignorado no primeiro caso.
Abram
29

Eu escrevi um pequeno script Python rápido que pode ser chamado a partir de uma linha de comando do bash. Leva o nome do módulo, classe e método que você deseja chamar e os parâmetros que deseja passar. Eu chamo PyRun e deixei a extensão .py e a tornei executável com chmod + x PyRun para que eu possa chamá-la rapidamente da seguinte maneira:

./PyRun PyTest.ClassName.Method1 Param1

Salve isso em um arquivo chamado PyRun

#!/usr/bin/env python
#make executable in bash chmod +x PyRun

import sys
import inspect
import importlib
import os

if __name__ == "__main__":
    cmd_folder = os.path.realpath(os.path.abspath(os.path.split(inspect.getfile( inspect.currentframe() ))[0]))
    if cmd_folder not in sys.path:
        sys.path.insert(0, cmd_folder)

    # get the second argument from the command line      
    methodname = sys.argv[1]

    # split this into module, class and function name
    modulename, classname, funcname = methodname.split(".")

    # get pointers to the objects based on the string names
    themodule = importlib.import_module(modulename)
    theclass = getattr(themodule, classname)
    thefunc = getattr(theclass, funcname)

    # pass all the parameters from the third until the end of 
    # what the function needs & ignore the rest
    args = inspect.getargspec(thefunc)
    z = len(args[0]) + 2
    params=sys.argv[2:z]
    thefunc(*params)

Aqui está um exemplo de módulo para mostrar como funciona. Isso é salvo em um arquivo chamado PyTest.py:

class SomeClass:
 @staticmethod
 def First():
     print "First"

 @staticmethod
 def Second(x):
    print(x)
    # for x1 in x:
    #     print x1

 @staticmethod
 def Third(x, y):
     print x
     print y

class OtherClass:
    @staticmethod
    def Uno():
        print("Uno")

Tente executar estes exemplos:

./PyRun PyTest.SomeClass.First
./PyRun PyTest.SomeClass.Second Hello
./PyRun PyTest.SomeClass.Third Hello World
./PyRun PyTest.OtherClass.Uno
./PyRun PyTest.SomeClass.Second "Hello"
./PyRun PyTest.SomeClass.Second \(Hello, World\)

Observe o último exemplo de escape dos parênteses para passar uma tupla como o único parâmetro para o segundo método.

Se você passar poucos parâmetros para o que o método precisa, você receberá um erro. Se você passar muitos, ignora os extras. O módulo deve estar na pasta de trabalho atual, pois o PyRun pode estar em qualquer lugar do seu caminho.

Joseph Gagliardo
fonte
2
É legal, mas não é realmente uma resposta para a pergunta.
Francis Colas
14
Eu peço desculpa mas não concordo; é exatamente a questão. Ele perguntou como você executa uma função a partir de um arquivo e é exatamente isso que isso faz.
Joseph Gagliardo
Você pode explicar o que está acontecendo com o cmd_folder?
RyanDay
26

adicione esse trecho ao final do seu script

def myfunction():
    ...


if __name__ == '__main__':
    globals()[sys.argv[1]]()

Agora você pode chamar sua função executando

python myscript.py myfunction

Isso funciona porque você está passando o argumento da linha de comando (uma sequência do nome da função) para localsum dicionário com uma tabela de símbolos local atual. Os parênteses no final farão com que a função seja chamada.

update: se você deseja que a função aceite um parâmetro na linha de comando, pode passar o sys.argv[2]seguinte:

def myfunction(mystring):
    print mystring


if __name__ == '__main__':
    globals()[sys.argv[1]](sys.argv[2])

Dessa forma, a execução python myscript.py myfunction "hello"será gerada hello.

Noam Hacker
fonte
É possível que esse método aceite um parâmetro para a função? Tais comomyfunction(12)
Major Major
@MajorMajor Eu atualizei a resposta para incluir como fazer isso
Noam Hacker
existe algum risco de fazer isso na produção ao vivo? Como quer fazê-lo como um teste de unidade.
Ardhi
9

Vamos tornar isso um pouco mais fácil para nós mesmos e apenas usar um módulo ...

Tentar: pip install compago

Então escreva:

import compago
app = compago.Application()

@app.command
def hello():
    print "hi there!"

@app.command
def goodbye():
    print "see ya later."

if __name__ == "__main__":
    app.run()

Então use assim:

$ python test.py hello
hi there!

$ python test.py goodbye
see ya later.

Nota: Há um bug no Python 3 no momento, mas funciona muito bem com o Python 2.

Edit: Uma opção ainda melhor, na minha opinião, é o módulo disparado pelo Google, que facilita também a passagem de argumentos de função. Está instalado com pip install fire. No GitHub:

Aqui está um exemplo simples.

import fire

class Calculator(object):
  """A simple calculator class."""

  def double(self, number):
    return 2 * number

if __name__ == '__main__':
  fire.Fire(Calculator)

Em seguida, na linha de comando, você pode executar:

python calculator.py double 10  # 20
python calculator.py double --number=15  # 30
Charles Clayton
fonte
+1. Fogo ainda tem uma maneira de chamar uma função sem alterar o script: python -m fire file_name method_name. Ele também possui um argparser embutido.
user3265569 24/04
6

Curiosamente, se o objetivo era imprimir no console da linha de comandos ou executar alguma outra operação python minuciosa, você pode canalizar a entrada no interpretador python da seguinte forma:

echo print("hi:)") | python

bem como arquivos de tubulação ..

python < foo.py

* Observe que a extensão não precisa ser .py para que o segundo funcione. ** Observe também que, para o bash, você pode precisar escapar dos caracteres

echo print\(\"hi:\)\"\) | python
Torie J
fonte
Considerando o exemplo foo.py com hello (), é assim que se pode usá-lo com a idéia acima. echo import foo;foo.hello() | python
Arindam Roychowdhury
Existe alguma maneira de passar argumentos de linha de comando com esse método?
precisa saber é o seguinte
11
FWIW, o seguinte é um pouco mais limpo para o terceiro exemplo:echo 'print("hi:)")' | python
user3166580
5

Se você instalar o pacote runp, pip install runpé necessário executar:

runp myfile.py hello

Você pode encontrar o repositório em: https://github.com/vascop/runp

vascop
fonte
11
O projeto não é compatível com o Python 3.
dim8 15/07/19
4

Eu tinha o requisito de usar vários utilitários python (intervalo, string etc.) na linha de comando e havia escrito a ferramenta pyfunc especificamente para isso. Você pode usá-lo para enriquecer sua experiência de uso da linha de comando:

 $ pyfunc -m range -a 1 7 2
 1
 3
 5

 $ pyfunc -m string.upper -a test
 TEST

 $ pyfunc -m string.replace -a 'analyze what' 'what' 'this'
 analyze this
Saurabh Hirani
fonte
1

É sempre uma opção para inserir python na linha de comando com o comando python

então importe seu arquivo, então importe exemplo_arquivo

em seguida, execute o comando com example_file.hello ()

Isso evita a estranha função de cópia .pyc que aparece toda vez que você executa python -c etc.

Talvez não seja tão conveniente quanto um comando único, mas uma boa solução rápida para enviar um arquivo de texto a partir da linha de comando, e permite que você use python para chamar e executar seu arquivo.

user2495144
fonte
1

Algo assim: call_from_terminal.py

# call_from_terminal.py
# Ex to run from terminal
# ip='"hi"'
# python -c "import call_from_terminal as cft; cft.test_term_fun(${ip})"
# or
# fun_name='call_from_terminal'
# python -c "import ${fun_name} as cft; cft.test_term_fun(${ip})"
def test_term_fun(ip):
    print ip

Isso funciona no bash.

$ ip='"hi"' ; fun_name='call_from_terminal' 
$ python -c "import ${fun_name} as cft; cft.test_term_fun(${ip})"
hi
Al Conrad
fonte
1

Abaixo está o arquivo Odd_Even_function.py que possui a definição da função.

def OE(n):
    for a in range(n):
        if a % 2 == 0:
            print(a)
        else:
            print(a, "ODD")

Agora, para chamar o mesmo no prompt de comando abaixo, estão as opções trabalhadas para mim.

Opções 1 Caminho completo da exe \ python.exe -c "import Odd_Even_function; Odd_Even_function.OE (100)"

Opção 2 Caminho completo do exe \ python.exe -c "de Odd_Even_function import OE; OE (100)"

Obrigado.

moxit mehta
fonte
0

Esta função não pode ser executada na linha de comando, pois retorna um valor que não será tratado. Você pode remover a devolução e usar a impressão

Shubham
fonte
-2

Use a ferramenta python-c ( pip install python-c ) e, em seguida, basta escrever:

$ python-c foo 'hello()'

ou caso você não tenha conflitos de nome de função nos arquivos python:

$ python-c 'hello()'
lua fraca
fonte
-2

Primeiro, você deve chamar a função como eles disseram ou o comando não exibirá nada na saída. Depois disso, salve o arquivo e copie o caminho do arquivo clicando com o botão direito do mouse na pasta do arquivo e clique em "copiar arquivo". vá para o terminal e escreva: - cd "o caminho do arquivo" - python "nome do arquivo, por exemplo (main.py)", depois disso ele exibirá a saída do seu código.

ShahadM
fonte
-4

Facilite sua vida, instale o Spyder. Abra seu arquivo e execute-o (clique na seta verde). Posteriormente, seu hello()método é definido e conhecido pelo IPython Console, para que você possa chamá-lo no console.

Ivana
fonte