Was ist der beste Weg, um ein Skript von einem anderen Skript aus aufzurufen?

307

Ich habe ein Skript namens test1.py, das sich nicht in einem Modul befindet. Es enthält nur Code, der ausgeführt werden soll, wenn das Skript selbst ausgeführt wird. Es gibt keine Funktionen, Klassen, Methoden usw. Ich habe ein anderes Skript, das als Dienst ausgeführt wird. Ich möchte test1.py über das Skript aufrufen, das als Dienst ausgeführt wird.

Zum Beispiel:

Datei test1.py

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

Datei service.py

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

Mir ist eine Methode bekannt, die darin besteht, die Datei zu öffnen, den Inhalt zu lesen und ihn im Grunde zu bewerten. Ich gehe davon aus, dass es einen besseren Weg gibt, dies zu tun. Zumindest hoffe ich es.

Josh Smeaton
quelle
42
Der bessere Weg ist, Methoden und Klassen zu schreiben und sie zu verwenden
Aamir
3
runpy.run_moduleNoch hat niemand eine Antwort gepostet ?!
Aran-Fey

Antworten:

279

Der übliche Weg, dies zu tun, ist ungefähr der folgende.

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
quelle
44
Was ist, wenn test1.pyes sich in einem weit entfernten Verzeichnis befindet?
Evgeni Sergeev
3
@ EvgeniSergeev Siehe stackoverflow.com/questions/67631/…
Evgeni Sergeev
18
Dies beantwortet die Frage jedoch nicht wirklich, oder? Sie führen nicht das gesamte Skript aus, sondern einige Funktionen aus dem importierten Skript heraus.
Gented
2
@GennaroTedesco: Du liegst falsch. Das import test1in service.pyführt tatsächlich das gesamte Skript aus (das in diesem Fall nur definiert, some_func()da __name__ == '__main__'dies Falseder Fall ist). Das klingt nach allem, was das OP tun möchte. Diese Antwort geht darüber hinaus, beantwortet aber definitiv die Frage - und noch einige mehr.
Martineau
2
Wenn beispielsweise test1.pydie Definition der Funktion nicht enthalten wäre some_func()(z. B. nur einige Codezeilen), print("hello")würde Ihr Code nicht funktionieren. In diesem Beispiel funktioniert dies, weil Sie im Wesentlichen eine externe Funktion importieren, die Sie anschließend zurückrufen.
Gented
144

Dies ist in Python 2 mit möglich

execfile("test2.py")

Informationen zum Umgang mit Namespaces finden Sie in der Dokumentation , falls dies in Ihrem Fall wichtig ist.

In Python 3 ist dies möglich (dank @fantastory)

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

Sie sollten jedoch einen anderen Ansatz in Betracht ziehen. Ihre Idee (soweit ich sehen kann) sieht nicht sehr sauber aus.

balpha
quelle
9
direkt was ich in Python 32 brauche es ist exec (open ('test2.py'). read ())
fantastisch
8
Dieser Ansatz führt die Skripte im aufrufenden Namespace aus. :)
dmvianna
6
Um Befehlszeilenargumente an das Skript zu übergeben, können Sie die sys.argvListe bearbeiten .
JFS
1
Umfassendere Behandlung von Python 3-Äquivalenten: stackoverflow.com/questions/436198/…
John Y
2
Dies akzeptiert keine Argumente (die an die PY-Datei übergeben werden sollen)!
Apostolos
70

Ein anderer Weg:

Datei test1.py:

print "test1.py"

Datei service.py:

import subprocess

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

Der Vorteil dieser Methode besteht darin, dass Sie kein vorhandenes Python-Skript bearbeiten müssen, um den gesamten Code in eine Unterroutine einzufügen.

Dokumentation: Python 2 , Python 3

Dick Goodwin
quelle
7
Ich musste verwenden subprocess.call("./test1.py", shell=True), um es zum
Laufen
5
Nicht verwenden, es shell=Truesei denn, es ist notwendig.
Piotr Dobrogost
2
@PiotrDobrogost - Können Sie angeben, welche Situationen dies erforderlich machen würden?
sancho.s ReinstateMonicaCellio
7
Es funktioniert nicht unter einem typischen Unix, bei dem sich das aktuelle Verzeichnis nicht in PATH befindet. test1.pysollte ausführbar sein und die shebang-Zeile ( #!/usr/bin/env python) haben, und Sie sollten den vollständigen Pfad angeben, oder Sie müssen die ausführbare Datei selbst bereitstellen: call([sys.executable, os.path.join(get_script_dir(), 'test1.py')])wo get_script_dir()wird hier definiert .
JFS
5
Oder subprocess.call(['python', 'test1.py']).
Big McLargeHuge
21

Wenn Sie möchten, dass test1.py mit derselben Funktionalität ausführbar bleibt wie beim Aufruf von service.py, gehen Sie wie folgt vor:

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
quelle
3
Was ist, wenn Sie Laufzeitparameter haben?
Gabriel Fair
13
import os

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

Mit os können Sie direkt an Ihr Terminal telefonieren. Wenn Sie noch spezifischer sein möchten, können Sie Ihre Eingabezeichenfolge mit lokalen Variablen verketten, d. H.

command = 'python myOtherScript.py ' + sys.argv[1] + ' ' + sys.argv[2]
os.system(command)
Alex Mapley
quelle
Anrufe os.systemsollten vermieden werden, Sie können das gleiche mit jeder Klasse vonPopen, Call,
user1767754
Aus der Python-Dokumentation : Das Unterprozessmodul bietet leistungsfähigere Funktionen zum Erstellen neuer Prozesse und zum Abrufen ihrer Ergebnisse. Die Verwendung dieses Moduls ist der Verwendung dieser Funktion vorzuziehen.
Big McLargeHuge
12

Sie sollten dies nicht tun. Tun Sie stattdessen:

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
quelle
1
Woher weiß es beim Importieren von test1, wo sich die Datei befindet? muss es sich im selben Verzeichnis befinden? Was ist, wenn es nicht ist?
NULL.Dude
8

Verwendung import test1für die erste Verwendung - das Skript wird ausgeführt. Behandeln Sie das Skript für spätere Aufrufe als importiertes Modul und rufen Sie die reload(test1)Methode auf.

Wann reload(module)wird ausgeführt:

  • Der Code der Python-Module wird neu kompiliert und der Code auf Modulebene erneut ausgeführt , wodurch eine neue Gruppe von Objekten definiert wird, die an Namen im Wörterbuch des Moduls gebunden sind. Die Init-Funktion von Erweiterungsmodulen wird nicht aufgerufen

Eine einfache Überprüfung von sys.moduleskann verwendet werden, um die entsprechende Aktion aufzurufen. 'test1'Verwenden Sie die integrierte Funktion ' import ()', um weiterhin auf den Skriptnamen als Zeichenfolge ( ) zu verweisen.

import sys
if sys.modules.has_key['test1']:
    reload(sys.modules['test1'])
else:
    __import__('test1')
Gimel
quelle
3
reloadist in Python 3 verschwunden.
Piotr Dobrogost
1
Das Importieren eines Moduls entspricht nicht dem Ausführen, z if __name__ == "__main__":. B. Guard. Es könnte andere subtilere Unterschiede geben. Lassen Sie keinen beliebigen Code auf globaler Ebene. Legen Sie es in einer Funktion und rufen sie nach dem Import als in der vorgeschlagenen akzeptierten Antwort statt
JFS
5

Ich bevorzuge 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
quelle
3

Warum nicht einfach test1 importieren? Jedes Python-Skript ist ein Modul. Ein besserer Weg wäre, eine Funktion zu haben, z. B. main / run in test1.py, import1 und import1.main (). Oder Sie können test1.py als Unterprozess ausführen.

Anurag Uniyal
quelle
3

Wie bereits erwähnt, runpyist dies eine gute Möglichkeit, andere Skripte oder Module über das aktuelle Skript auszuführen.

Übrigens ist es durchaus üblich, dass ein Tracer oder Debugger dies tut, und unter solchen Umständen funktionieren Methoden wie das direkte Importieren der Datei oder das Ausführen der Datei in einem Unterprozess normalerweise nicht.

Es muss auch beachtet werden exec, um den Code auszuführen. Sie müssen die richtigen run_globalsAngaben machen, um Importfehler oder andere Probleme zu vermeiden. Siehe runpy._run_codefür weitere Einzelheiten.

Chao Chen
quelle
0

Dies ist ein Beispiel mit subprocessBibliothek:

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
quelle
1
Das Ausführen von Python als Teilprozess von Python ist fast nie die richtige Lösung. Wenn Sie sich für einen Unterprozess entscheiden, sollten Sie dies vermeiden, es Popensei denn, die übergeordneten Funktionen können wirklich nicht das tun, was Sie wollen. In diesem Fall check_calloder runwürde alles tun, was Sie brauchen und mehr, mit wesentlich weniger Installation in Ihrem eigenen Code.
Tripleee
0

Dieser Prozess ist etwas unorthodox, würde aber in allen Python-Versionen funktionieren.

Angenommen, Sie möchten ein Skript mit dem Namen 'empfehle.py' in einer 'if'-Bedingung ausführen und dann Folgendes verwenden:

if condition:
       import recommend

Die Technik ist anders, funktioniert aber!

Ashwin Balani
quelle