Qual é a melhor maneira de chamar um script de outro script?

307

Eu tenho um script chamado test1.py que não está em um módulo. Apenas possui código que deve ser executado quando o próprio script for executado. Não há funções, classes, métodos, etc. Eu tenho outro script que é executado como um serviço. Quero chamar test1.py a partir do script em execução como um serviço.

Por exemplo:

Arquivo test1.py

print "I am a test"
print "see! I do nothing productive."

Arquivo service.py

# Lots of stuff here
test1.py # do whatever is in test1.py

Estou ciente de um método que está abrindo o arquivo, lendo o conteúdo e basicamente avaliando-o. Estou assumindo que há uma maneira melhor de fazer isso. Ou pelo menos espero que sim.

Josh Smeaton
fonte
42
A melhor maneira é métodos de gravação e classes e usá-los
Aamir
3
Ninguém postou uma runpy.run_moduleresposta ainda ?!
Aran-Fey

Respostas:

279

A maneira usual de fazer isso é algo como o seguinte.

test1.py

def some_func():
    print 'in test 1, unproductive'

if __name__ == '__main__':
    # test1.py executed as script
    # do something
    some_func()

service.py

import test1

def service_func():
    print 'service func'

if __name__ == '__main__':
    # service.py executed as script
    # do something
    service_func()
    test1.some_func()
ars
fonte
44
E se test1.pyestiver localizado em algum diretório distante?
Evgeni Sergeev
3
@EvgeniSergeev Veja stackoverflow.com/questions/67631/…
Evgeni Sergeev
18
Isso realmente não responde à pergunta, não é? Você não está executando o script inteiro, está executando algumas funções de dentro do script que importa.
gented
2
@GennaroTedesco: Você está enganado. O import test1in service.pyrealmente executa o script inteiro (que apenas define some_func()uma vez que __name__ == '__main__'será Falsenesse caso). Parece que todo o OP quer fazer. Essa resposta vai além disso, mas definitivamente responde à pergunta - e mais algumas.
martineau
2
Se, digamos, test1.pynão contivesse a definição da função some_func()(mas apenas algumas linhas de código, por exemplo print("hello")), seu código não funcionaria. Neste exemplo em particular, ele funciona porque você está importando essencialmente uma função externa que depois será chamada de volta.
gented
144

Isso é possível no Python 2 usando

execfile("test2.py")

Consulte a documentação para lidar com espaços para nome, se importante no seu caso.

No Python 3, isso é possível usando (graças a @fantastory)

exec(open("test2.py").read())

No entanto, você deve considerar o uso de uma abordagem diferente; sua ideia (pelo que posso ver) não parece muito limpa.

balpha
fonte
9
diretamente o que eu preciso em python 32 é exec (open ( 'test2.py') read ().)
fantastory
8
Essa abordagem executa os scripts no espaço para nome da chamada. :)
dmvianna
6
Para passar argumentos da linha de comando para o script, você pode editar a sys.argvlista.
JFS
1
Tratamento mais abrangente sobre Python 3 equivalentes: stackoverflow.com/questions/436198/...
John Y
2
Isso não aceita argumentos (a serem passados ​​para o arquivo PY)!
Apostolos
70

Outra maneira:

Arquivo test1.py:

print "test1.py"

Arquivo service.py:

import subprocess

subprocess.call("test1.py", shell=True)

A vantagem desse método é que você não precisa editar um script Python existente para colocar todo o seu código em uma sub-rotina.

Documentação: Python 2 , Python 3

Dick Goodwin
fonte
7
Eu tive que usar subprocess.call("./test1.py", shell=True)para fazer o trabalho
asmaier
5
Não use a shell=Truemenos que seja necessário.
Piotr Dobrogost
2
@PiotrDobrogost - Você poderia especificar quais situações seriam necessárias?
sancho.s ReinstateMonicaCellio
7
Não funcionará em um Unix típico, onde o diretório atual não está no PATH. test1.pydeve ser executável e ter a linha shebang ( #!/usr/bin/env python) e você deve especificar o caminho completo ou precisar fornecer o executável: call([sys.executable, os.path.join(get_script_dir(), 'test1.py')])onde get_script_dir()é definido aqui .
JFS
5
Or subprocess.call(['python', 'test1.py']).
Big McLargeHuge
21

Se você deseja que o test1.py permaneça executável com a mesma funcionalidade de quando é chamado dentro de service.py, faça algo como:

test1.py

def main():
    print "I am a test"
    print "see! I do nothing productive."

if __name__ == "__main__":
    main()

service.py

import test1
# lots of stuff here
test1.main() # do whatever is in test1.py
Michael Schneider
fonte
3
E se você tiver parâmetros de tempo de execução?
Gabriel Fair
13
import os

os.system("python myOtherScript.py arg1 arg2 arg3")  

Usando o, você pode fazer chamadas diretamente para o seu terminal. Se você quiser ser ainda mais específico, pode concatenar sua string de entrada com variáveis ​​locais, ie.

command = 'python myOtherScript.py ' + sys.argv[1] + ' ' + sys.argv[2]
os.system(command)
Alex Mapley
fonte
chamadas para os.systemdevem ser evitadas, você pode fazer o mesmo com qualquer classe dePopen, Call,
user1767754 5/18
Da documentação do Python : O módulo de subprocesso fornece recursos mais poderosos para gerar novos processos e recuperar seus resultados; usar esse módulo é preferível a usar esta função.
Big McLargeHuge
12

Você não deveria estar fazendo isso. Em vez disso, faça:

test1.py:

 def print_test():
      print "I am a test"
      print "see! I do nothing productive."

service.py

#near the top
from test1 import print_test
#lots of stuff here
print_test()
thedz
fonte
1
Quando você importa o test1, como ele sabe onde está o arquivo? precisa estar no mesmo diretório? e se não for?
precisa saber é o seguinte
8

Use import test1para o 1º uso - ele executará o script. Para chamadas posteriores, trate o script como um módulo importado e chame o reload(test1)método

Quando reload(module)é executado:

  • O código dos módulos Python é recompilado e o código no nível do módulo reexecutado , definindo um novo conjunto de objetos vinculados a nomes no dicionário do módulo. A função init dos módulos de extensão não é chamada

Uma simples verificação de sys.modulespode ser usada para chamar a ação apropriada. Para continuar se referindo ao nome do script como uma string ( 'test1'), use o ' import ()' interno.

import sys
if sys.modules.has_key['test1']:
    reload(sys.modules['test1'])
else:
    __import__('test1')
gimel
fonte
3
reloadse foi em Python 3.
Piotr Dobrogost
1
importar um módulo não é equivalente a executá-lo, por exemplo, considere a if __name__ == "__main__":proteção. Pode haver outras diferenças mais sutis. Não deixe código arbitrário em nível global. Coloque-o em uma função e chamá-lo após a importação como sugerido na resposta aceita vez
JFS
5

Eu prefiro runpy :

#!/usr/bin/env python
# coding: utf-8

import runpy

runpy.run_path(path_name='script-01.py')
runpy.run_path(path_name='script-02.py')
runpy.run_path(path_name='script-03.py')
Flavio
fonte
3

Por que não apenas importar test1? Todo script python é um módulo. Uma maneira melhor seria ter uma função, por exemplo, main / run em test1.py, importar test1 e executar test1.main (). Ou você pode executar test1.py como um subprocesso.

Anurag Uniyal
fonte
3

Como já foi mencionado, runpyé uma boa maneira de executar outros scripts ou módulos a partir do script atual.

A propósito, é bastante comum que um rastreador ou depurador faça isso e, em tais circunstâncias, métodos como importar o arquivo diretamente ou executá-lo em um subprocesso geralmente não funcionam.

Ele também precisa de atenção execpara executar o código. Você deve fornecer o adequado run_globalspara evitar erros de importação ou outros problemas. Consulte runpy._run_codepara detalhes.

Chao Chen
fonte
0

Este é um exemplo com a subprocessbiblioteca:

import subprocess

python_version = '3'
path_to_run = './'
py_name = '__main__.py'

# args = [f"python{python_version}", f"{path_to_run}{py_name}"]  # Avaible in python3
args = ["python{}".format(python_version), "{}{}".format(path_to_run, py_name)]

res = subprocess.Popen(args, stdout=subprocess.PIPE)
output, error_ = res.communicate()

if not error_:
    print(output)
else:
    print(error_)
Benyamin Jafari
fonte
1
Executar o Python como um subprocesso do Python quase nunca é a solução correta. Se você seguir um subprocesso, evite Popen, a menos que as funções de nível superior realmente não possam fazer o que deseja. Nesse caso, check_callou runfaria tudo o que você precisa e muito mais, com substancialmente menos encanamento em seu próprio código.
tripleee
0

Esse processo é um pouco ortodoxo, mas funcionaria em todas as versões python,

Suponha que você queira executar um script chamado 'recommend.py' dentro de uma condição 'if' e, em seguida, use,

if condition:
       import recommend

A técnica é diferente, mas funciona!

Ashwin Balani
fonte