Jaki jest najlepszy sposób na wywołanie skryptu z innego skryptu?

307

Mam skrypt o nazwie test1.py, który nie znajduje się w module. Ma tylko kod, który powinien zostać wykonany po uruchomieniu samego skryptu. Nie ma żadnych funkcji, klas, metod itp. Mam inny skrypt, który działa jako usługa. Chcę wywołać test1.py ze skryptu działającego jako usługa.

Na przykład:

Plik test1.py

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

Plik service.py

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

Zdaję sobie sprawę z jednej metody, która polega na otwarciu pliku, odczytaniu zawartości i jej ewaluacji. Zakładam, że jest na to lepszy sposób. A przynajmniej mam taką nadzieję.

Josh Smeaton
źródło
42
Lepszym sposobem jest pisanie metod i klas i korzystanie z nich
Aamir
3
Nikt jeszcze nie opublikował runpy.run_moduleodpowiedzi ?!
Aran-Fey

Odpowiedzi:

279

Zwykle jest to możliwe w następujący sposób.

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
źródło
44
Co jeśli test1.pyznajduje się w odległym katalogu?
Evgeni Sergeev,
3
@EvgeniSergeev Patrz stackoverflow.com/questions/67631/…
Evgeni Sergeev
18
To tak naprawdę nie odpowiada na pytanie, prawda? Nie wykonujesz całego skryptu, wykonujesz niektóre funkcje z importowanego skryptu.
gented
2
@GennaroTedesco: Mylisz się. Program import test1in service.pyfaktycznie wykonuje cały skrypt (który tylko definiuje, some_func()ponieważ __name__ == '__main__'będzie Falsew tym przypadku). To brzmi jak wszystko, co OP chce zrobić. Ta odpowiedź wykracza poza to, ale zdecydowanie odpowiada na pytanie - a potem niektóre.
martineau,
2
Jeśli, powiedzmy, test1.pynie zawiera definicji funkcji some_func()(ale na przykład tylko kilka wierszy kodu print("hello")), wówczas twój kod nie działałby. W tym konkretnym przykładzie działa, ponieważ zasadniczo importujesz funkcję zewnętrzną, którą następnie oddzwaniasz.
gented
144

Jest to możliwe w Pythonie 2 przy użyciu

execfile("test2.py")

Zajrzyj do dokumentacji dotyczącej obsługi przestrzeni nazw, jeśli jest to ważne w twoim przypadku.

W Pythonie 3 jest to możliwe przy użyciu (dzięki @fantastory)

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

Należy jednak rozważyć zastosowanie innego podejścia; twój pomysł (z tego co widzę) nie wygląda na bardzo czysty.

balpha
źródło
9
bezpośrednio to, czego potrzebuję w Pythonie 32, to exec (open ('test2.py'). read ())
fantastory
8
To podejście wykonuje skrypty w przestrzeni nazw wywołujących. :)
dmvianna
6
aby przekazać do skryptu argumenty wiersza poleceń, możesz edytować sys.argvlistę.
jfs
1
Bardziej kompleksowe traktowanie ekwiwalentów Pythona 3: stackoverflow.com/questions/436198/...
John Y
2
To nie akceptuje argumentów (do przekazania do pliku PY)!
Apostolos,
70

Inny sposób:

Plik test1.py:

print "test1.py"

Plik service.py:

import subprocess

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

Zaletą tej metody jest to, że nie trzeba edytować istniejącego skryptu Python, aby umieścić cały jego kod w podprogramie.

Dokumentacja: Python 2 , Python 3

Dick Goodwin
źródło
7
Musiałem użyć, subprocess.call("./test1.py", shell=True)aby to zadziałało
asmaier
5
Nie używaj, shell=Truechyba że jest to konieczne.
Piotr Dobrogost
2
@PiotrDobrogost - Czy możesz określić, które sytuacje spowodują, że będzie to konieczne?
sancho.s ReinstateMonicaCellio
7
Nie będzie działać na typowym Uniksie, w którym bieżący katalog nie znajduje się w zmiennej PATH. test1.pypowinien być wykonywalny i mieć linię shebang ( #!/usr/bin/env python) oraz powinieneś podać pełną ścieżkę, albo sam musisz podać plik wykonywalny: call([sys.executable, os.path.join(get_script_dir(), 'test1.py')])gdzie get_script_dir()jest zdefiniowany tutaj .
jfs
5
Lub subprocess.call(['python', 'test1.py']).
Big McLargeHuge
21

Jeśli chcesz, aby plik test1.py pozostawał wykonywalny z taką samą funkcjonalnością, jak w przypadku wywołania service.py, wykonaj następujące czynności:

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
źródło
3
Co się stanie, jeśli masz parametry środowiska wykonawczego?
Gabriel Fair
13
import os

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

Korzystając z systemu operacyjnego, możesz nawiązywać połączenia bezpośrednio z terminalem. Jeśli chcesz być jeszcze bardziej szczegółowy, możesz połączyć swój ciąg wejściowy ze zmiennymi lokalnymi, tj.

command = 'python myOtherScript.py ' + sys.argv[1] + ' ' + sys.argv[2]
os.system(command)
Alex Mapley
źródło
połączeń os.systemnależy unikać, możesz zrobić to samo z dowolną klasą odPopen, Call,
user1767754
Z dokumentacji Pythona : Moduł podprocesu zapewnia bardziej zaawansowane funkcje do tworzenia nowych procesów i wyszukiwania ich wyników; korzystanie z tego modułu jest lepsze niż korzystanie z tej funkcji.
Big McLargeHuge
12

Nie powinieneś tego robić. Zamiast tego wykonaj:

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
źródło
1
kiedy importujesz test1, skąd ma wiedzieć, gdzie jest plik? czy musi być w tym samym katalogu? co jeśli nie?
NULL.Dude
8

Użyj import test1do pierwszego użycia - wykona skrypt. W przypadku późniejszych wywołań traktuj skrypt jako zaimportowany moduł i wywołaj reload(test1)metodę.

Kiedy reload(module)jest wykonywany:

  • Kod modułów Pythona jest ponownie kompilowany, a kod na poziomie modułu ponownie wykonywany , definiując nowy zestaw obiektów, które są powiązane z nazwami w słowniku modułu. Funkcja init modułów rozszerzeń nie jest wywoływana

sys.modulesMożna użyć prostej kontroli, aby wywołać odpowiednią akcję. Aby nadal odwoływać się do nazwy skryptu jako ciągu ( 'test1'), użyj wbudowanego polecenia import ()” .

import sys
if sys.modules.has_key['test1']:
    reload(sys.modules['test1'])
else:
    __import__('test1')
gimel
źródło
3
reloadzniknął w Pythonie 3.
Piotr Dobrogost
1
import modułu nie jest równoważny z uruchomieniem go, np. rozważ if __name__ == "__main__":ochronę. Mogą występować inne subtelniejsze różnice. Nie pozostawiaj niepożądanego kodu na poziomie globalnym. Zamiast tego należy wprowadzić funkcję i wywołać ją po imporcie, zgodnie z sugestią zawartą w zaakceptowanej odpowiedzi
jfs
5

Wolę 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
źródło
3

Dlaczego nie po prostu zaimportować test1? Każdy skrypt Pythona jest modułem. Lepszym sposobem byłoby posiadanie funkcji np. Main / run w test1.py, import test1 i run test1.main (). Lub możesz wykonać test1.py jako podproces.

Anurag Uniyal
źródło
3

Jak już wspomniano, runpy jest to dobry sposób na uruchomienie innych skryptów lub modułów z bieżącego skryptu.

Nawiasem mówiąc, śledzenie lub debugowanie jest dość powszechne, a w takich okolicznościach metody takie jak importowanie pliku bezpośrednio lub uruchamianie pliku w podprocesie zwykle nie działają.

Do execuruchomienia kodu należy również zwrócić uwagę . Musisz podać odpowiednie, run_globalsaby uniknąć błędu importu lub innych problemów. Zobacz runpy._run_codeszczegóły.

Chao Chen
źródło
0

To jest przykład z subprocessbiblioteką:

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
źródło
1
Uruchamianie Pythona jako podprocesu Pythona prawie nigdy nie jest właściwym rozwiązaniem. Jeśli wybierzesz podproces, powinieneś unikać, Popenchyba że funkcje wyższego poziomu naprawdę nie mogą zrobić tego, co chcesz. W takim przypadku, check_calllub runzrobiłby wszystko, czego potrzebujesz i więcej, przy znacznie mniejszej ilości hydrauliki we własnym kodzie.
tripleee
0

Ten proces jest nieco nie ortodoksyjny, ale działałby we wszystkich wersjach Pythona,

Załóżmy, że chcesz wykonać skrypt o nazwie „zalecana.py” w warunku „jeśli”, a następnie użyj,

if condition:
       import recommend

Technika jest inna, ale działa!

Ashwin Balani
źródło