Kann ich in Python main () eines importierten Moduls aufrufen?

84

In Python habe ich ein Modul myModule.py, in dem ich einige Funktionen definiere, und ein main () , das einige Befehlszeilenargumente akzeptiert .

Normalerweise rufe ich main () aus einem Bash-Skript auf. Jetzt möchte ich alles in ein kleines Paket packen , also dachte ich, ich könnte vielleicht mein einfaches Bash-Skript in ein Python-Skript verwandeln und es in das Paket einfügen.

Wie rufe ich die main () - Funktion von myModule.py von der main () - Funktion von MyFormerBashScript.py aus auf? Kann ich das überhaupt machen? Wie übergebe ich irgendwelche Argumente ?

Ricky Robinson
quelle
Wenn Sie myModule importiert haben, sollten Sie anrufen können myModule.main(). Was hast du bisher versucht?
Marius
Ich mache mir Sorgen um die Eingabeargumente, die ich normalerweise von einem Shell-Skript übergebe.
Ricky Robinson
Ist es sinnvoll, es mit dem subprocessModul aufzurufen ?
BenDundee
Ich denke, es wäre einfacher, ja.
Ricky Robinson

Antworten:

113

Es ist nur eine Funktion. Importieren Sie es und nennen Sie es:

import myModule

myModule.main()

Wenn Sie Argumente analysieren müssen, haben Sie zwei Möglichkeiten:

  • Analysieren Sie sie main(), übergeben Sie sie jedoch sys.argvals Parameter (der gesamte Code unten im selben Modul myModule):

    def main(args):
        # parse arguments using optparse or argparse or what have you
    
    if __name__ == '__main__':
        import sys
        main(sys.argv[1:])
    

    Jetzt können Sie myModule.main(['arg1', 'arg2', 'arg3'])aus einem anderen Modul importieren und aufrufen .

  • Haben Sie main()akzeptieren Parameter , die bereits analysiert werden (wieder den gesamten Code in dem myModuleModul):

    def main(foo, bar, baz='spam'):
        # run with already parsed arguments
    
    if __name__ == '__main__':
        import sys
        # parse sys.argv[1:] using optparse or argparse or what have you
        main(foovalue, barvalue, **dictofoptions)
    

    Importieren und Aufrufen an myModule.main(foovalue, barvalue, baz='ham')anderer Stelle und Übergeben von Python-Argumenten nach Bedarf.

Der Trick hier besteht darin, zu erkennen, wann Ihr Modul als Skript verwendet wird. Wenn Sie eine Python-Datei als Hauptskript ( python filename.py) ausführen, wird keine importAnweisung verwendet, daher ruft Python dieses Modul auf "__main__". Wenn derselbe filename.pyCode jedoch als module ( import filename) behandelt wird, verwendet Python diesen stattdessen als Modulnamen. In beiden Fällen ist die Variable __name__festgelegt, und wenn Sie sie testen, erfahren Sie, wie Ihr Code ausgeführt wurde.

Martijn Pieters
quelle
3
Sicher. Aber was ist mit den Eingabeargumenten? Ich benutze argparse, also wenn ich das Skript von einem Terminal aus aufrufe, tue ich es $ python myModule -a input_a -b input_b --parameterC input_c. Wie würde es innerhalb von Python-Code funktionieren? Das konnte ich bei einer einfachen Suche nicht finden.
Ricky Robinson
@ RickyRobinson: erweitert, um zu zeigen, dass Sie es in beide Richtungen haben können; Geben Sie einfach die Argumente ein, die analysiert oder analysiert werden sollen.
Martijn Pieters
1
Vielen Dank. Könnten Sie bitte auch angeben, welcher Code-Auszug zu welchem ​​Modul oder Skript gehört? Es sieht viel umständlicher aus als ich am Anfang dachte.
Ricky Robinson
@ RickyRobinson: Beide Auszüge gehören im selben Modul zusammen; Ich habe das explizit gemacht.
Martijn Pieters
41

Martijens Antwort macht Sinn, aber es fehlte etwas Entscheidendes, das anderen offensichtlich erscheinen mag, aber für mich schwer herauszufinden war.

In der Version, in der Sie argparse verwenden, muss diese Zeile im Hauptteil enthalten sein.

args = parser.parse_args(args)

Wenn Sie argparse nur in einem Skript verwenden, schreiben Sie normalerweise nur

args = parser.parse_args()

und parse_args finden die Argumente über die Befehlszeile. In diesem Fall hat die Hauptfunktion jedoch keinen Zugriff auf die Befehlszeilenargumente. Sie müssen argparse daher mitteilen, um welche Argumente es sich handelt.

Hier ist ein Beispiel

import argparse
import sys

def x(x_center, y_center):
    print "X center:", x_center
    print "Y center:", y_center

def main(args):
    parser = argparse.ArgumentParser(description="Do something.")
    parser.add_argument("-x", "--xcenter", type=float, default= 2, required=False)
    parser.add_argument("-y", "--ycenter", type=float, default= 4, required=False)
    args = parser.parse_args(args)
    x(args.xcenter, args.ycenter)

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

Angenommen, Sie haben diese Datei mytest.py genannt. Um sie auszuführen, können Sie entweder eine dieser Aktionen über die Befehlszeile ausführen

python ./mytest.py -x 8
python ./mytest.py -x 8 -y 2
python ./mytest.py 

welches jeweils zurückkehrt

X center: 8.0
Y center: 4

oder

X center: 8.0
Y center: 2.0

oder

X center: 2
Y center: 4

Oder wenn Sie ein anderes Python-Skript ausführen möchten, können Sie dies tun

import mytest
mytest.main(["-x","7","-y","6"]) 

was zurückkehrt

X center: 7.0
Y center: 6.0
Barry Solomon
quelle
4
Dies ist genau das, was ich brauchte - vielen Dank für den hilfreichen Nachtrag
HFBrowning
Dies mag mit Python 2 funktioniert haben, aber in Python 3 funktioniert es nicht mehr. Die main () - Funktion eines Moduls kann nicht aufgerufen werden:AttributeError: module 'sqlacodegen' has no attribute 'main'
NaturalBornCamper
24

Es hängt davon ab, ob. Wenn der Hauptcode durch ein ifwie in geschützt ist :

if __name__ == '__main__':
    ...main code...

dann nein, Sie können Python nicht dazu bringen, dies auszuführen, da Sie die automatische Variable nicht beeinflussen können __name__.

Wenn sich der gesamte Code in einer Funktion befindet, ist dies möglicherweise möglich. Versuchen

import myModule

myModule.main()

Dies funktioniert auch dann, wenn sich das Modul mit einem schützt __all__.

from myModule import *Möglicherweise wird es mainfür Sie nicht sichtbar, sodass Sie das Modul selbst importieren müssen.

Aaron Digulla
quelle
Oh ok, danke für die Klarstellung. Ich habe alles in eine main () -Funktion eingefügt, also sollte es in Ordnung sein. Ich bin mehr besorgt darüber, wie Eingabeargumente an diese "zweite" Hauptleitung übergeben werden. Gibt es eine einfache Möglichkeit, dies zu tun?
Ricky Robinson
Sicher:import sys; module.main(sys.argv);
Aaron Digulla
Dies ist eine großartige alternative Erklärung für den Zugriff, __main__die mir geholfen hat, danke @AaronDigulla
Charlie G
Hier ist ein Trick, um eine Hauptleitung von einer anderen Funktion aufzurufen
PatriceG
3

Ich hatte das gleiche Bedürfnis auch mit argparse. Die parse_argsFunktion einer argparse.ArgumentParserObjektinstanz übernimmt implizit ihre Argumente standardmäßig von sys.args. Die Umgehung, die der Martijn-Linie folgt, besteht darin, dies explizit zu machen, sodass Sie die Argumente ändern können, an die Sie parse_argsals Wunsch übergeben.

def main(args):
    # some stuff
    parser = argparse.ArgumentParser()
    # some other stuff
    parsed_args = parser.parse_args(args)
    # more stuff with the args

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

Der entscheidende Punkt ist die Übergabe von Argumenten an die parse_argsFunktion. Um später die Hauptleitung zu verwenden, tun Sie einfach, was Martijn sagt.

eguaio
quelle
3

Die Antwort, nach der ich gesucht habe, wurde hier beantwortet: Wie verwende ich Python Argparse mit anderen Argumenten als sys.argv?

Wenn main.pyund parse_args()auf diese Weise geschrieben ist, kann das Parsen gut durchgeführt werden

# main.py
import argparse
def parse_args():
    parser = argparse.ArgumentParser(description="")
    parser.add_argument('--input', default='my_input.txt')
    return parser

def main(args):
    print(args.input)

if __name__ == "__main__":
    parser = parse_args()
    args = parser.parse_args()
    main(args)

Dann können Sie main()Argumente parser.parse_args(['--input', 'foobar.txt'])in einem anderen Python-Skript aufrufen und damit analysieren :

# temp.py
from main import main, parse_args
parser = parse_args()
args = parser.parse_args([]) # note the square bracket
# to overwrite default, use parser.parse_args(['--input', 'foobar.txt'])
print(args) # Namespace(input='my_input.txt')
main(args)
Sida Zhou
quelle
0

Angenommen, Sie versuchen, auch die Befehlszeilenargumente zu übergeben.

import sys
import myModule


def main():
    # this will just pass all of the system arguments as is
    myModule.main(*sys.argv)

    # all the argv but the script name
    myModule.main(*sys.argv[1:])
beforeebel
quelle
Vielen Dank. Ich benutze eigentlich argparsestatt sys.argv. Wie würde sich das in diesem Fall ändern? Außerdem möchte ich vom äußeren Skript nur einige Eingabeargumente übergeben, die der Benutzer eingibt, während andere Eingabeargumente für das innere Skript (myModule.py) von mir fest codiert werden.
Ricky Robinson
Ohne den Code selbst zu sehen, ist es schwierig, Einzelheiten zu beantworten. Im Allgemeinen würden Sie nur die Argumente übergeben. Das *entpackt ein Array f(a) => f([1,2,3])gegen f(*a) => f(1,2,3) Sie könnten genauso einfach tun myModule.main(sys.argv[1], "other value", 39)oder was auch immer.
24.