Ausführen von Python-Skripten (mit Parametern) in einem anderen Python-Skript mit ArcPy?

23

Ein in AML häufig verwendetes Codierungsmuster bestand darin, eine AML (mit Parametern) in einer anderen AML auszuführen.

Eine Anwendung, die ich gerade entwickle, würde davon profitieren, ein Python-Skript (mit Parametern) in einem anderen Python-Skript ausführen zu können.

Dies scheint jedoch überhaupt nicht einfach zu sein.

In ArcGIS 10 experimentiere ich mit dem Umschließen des "inneren" Python-Skripts in ein ArcGIS-Tool mit den Parametern. Ich dachte, es wäre eine einfache Sache, das "äußere" Python-Skript arcpy.ImportToolbox verwenden zu lassen, um die Toolbox zu importieren und dann das (die) Tool (s) darin auszuführen. Beim bisherigen Testen scheinen jedoch alle meine Versuche, das "innere" Werkzeug über das "äußere" Skript auszuführen, das "innere" Werkzeug einfach zu überspringen (es wird kein Fehler ausgegeben).

Hier ist ein Testcode, um besser zu veranschaulichen, was ich zu beschreiben versuche.

Mein testinner.py Skript ist:

inputString = arcpy.GetParameterAsText(0)

newFC = "C:\\Temp\\test.gdb\\" + inputString
arcpy.Copy_management("C:\\Temp\\test.gdb\\test",newFC)

Mein testouter.py Skript ist:

import arcpy

inputString1 = arcpy.GetParameterAsText(0)
inputString2 = arcpy.GetParameterAsText(1)

arcpy.ImportToolbox("C:\\Temp\\test.tbx")

arcpy.testinner_test(inputString1)

arcpy.testinner_test(inputString2)

Für testinner.py benötigt das Tool einen einzelnen String-Parameter.

Für testouter.py benötigt das Tool zwei String-Parameter

Die beiden Tools befinden sich in einer test.tbx.

Die test.gdb benötigt nur eine einzelne leere Feature-Class namens test.

Wenn Sie das obige zusammengestellt haben und das Testinner-Tool mit einer Zeichenfolge wie 'abc' als Parameter ausführen, wird die Feature-Class 'test' in eine Zeichenfolge mit dem Namen 'abc' OK kopiert.

Wenn Sie jedoch versuchen, das Testouter-Tool mit zwei Zeichenfolgen wie "uvw" und "xyz" als Parameter auszuführen, wird das Testinner-Tool in "testouter.py" anscheinend einmal in Ordnung ausgeführt, sendet ArcMap 10 SP2 unter Vista SP2 jedoch bei einem schwerwiegenden Anwendungsfehler versuche es das zweite mal zu benutzen.

Der gleiche Test unter Windows XP SP3 und ArcGIS Desktop 10 SP2 führt zum gleichen Zeitpunkt auch zu einem schwerwiegenden Anwendungsfehler.

PolyGeo
quelle
2
Wenn Sie die Antwort von @ Dan dazu lesen, dann stellen Sie sich .py-Dateien nicht nur als "Skripte" vor, sondern als Module, die Sie wiederverwenden und recyceln können, indem Sie die benötigten Funktionen und Klassen aus diesen Modulen importieren. Extrahieren Sie diese verschachtelten GP-Parameter, indem Sie einen Parametersatz mit einem Skript einlesen und dann nach Bedarf Funktionen in Ihren anderen Modulen aufrufen. Verwenden Sie den Haupttrick if name __ == '__ ' , um Ihre Module sowohl importierbar als auch noch verwendbar zu machen.
blah238
Ich habe Dans Beispiel für die Ausgabe: C: \ Temp \ Main_program.py ('Summe einiger Zahlen:', 55) ('Summe der Quadrate:', 385) ('Hallo von 8:', [1, 2, 3) , 4, 5, 6, 7, 8, 9, 10]), aber ich habe Mühe, es an ein ArcPy-Beispiel anzupassen, wie ich es oben angegeben habe. Jede weitere Hilfe, wie ein ArcPy-Beispiel aussehen würde, wäre sehr dankbar.
PolyGeo
Siehe die Antwort, die ich hinzugefügt habe - soll helfen, die Dinge im Kontext Ihres Beispiels besser zu erklären.
blah238
Ich bin gerade auf einen ausgezeichneten Blog-Beitrag von Jason Pardy gestoßen, der eine ArcPy-Vorlage mit dem Codierungsmuster für Python-Module unter blogs.esri.com/Dev/blogs/geoprocessing/archive/2011/07/21/…
PolyGeo
Dieser Link ist seitdem umgezogen, und ich glaube, er ruht jetzt hier: blogs.esri.com/esri/arcgis/2011/08/04/pythontemplate
ndimhypervol

Antworten:

15

Hier ist Ihr Testbeispiel geändert, um ein "Dienstprogramm" -Modul innerhalb des Hauptskripts zu importieren und eine Funktion mit den vom Skript-Tool eingelesenen Parametern aufzurufen:


CopyFeaturesTool.py - Skriptwerkzeug , das Parameter einliest und eine Funktion in einem anderen Modul aufruft

import CopyFeaturesUtility
import arcpy

inputFC = arcpy.GetParameterAsText(0)
outputFCName = arcpy.GetParameterAsText(1)
CopyFeaturesUtility.copyFeaturesToTempGDB(inputFC, outputFCName)

CopyFeaturesUtility.py - Modul mit einer einzigen Funktion copyFeaturesToTempGDB. Kann entweder importiert oder eigenständig ausgeführt werden. Bei Ausführung als eigenständige Installation wird der Code unter if __name__ == '__main__'ausgeführt.

import arcpy
import os

def copyFeaturesToTempGDB(inputFeatures, outputName):
    """Copies the input features to a temporary file geodatabase.
    inputFeatures: The input feature class or layer.
    outputName: The name to give the output feature class."""

    tempGDB = r"c:\temp\test.gdb"
    newFC = os.path.join(tempGDB, outputName)
    arcpy.env.overwriteOutput = True
    arcpy.CopyFeatures_management(inputFeatures, newFC)

if __name__ == '__main__':
    inputFC = r"c:\temp\test.gdb\test"
    outputFCName = "testCopy"
    copyFeaturesToTempGDB(inputFC, outputFCName)

Ich denke, Sie werden feststellen, dass dieser modulare Ansatz viel effizienter und logischer ist, wenn Sie sich erst einmal daran gewöhnt haben. Der Abschnitt "Module" im Standard-Python-Lernprogramm ist auch eine gute Quelle, um zu verstehen, wie der Import funktioniert.

Weitere arcpy-spezifische Beispiele finden Sie in den integrierten Skripten in Ihrem C:\Program Files\ArcGIS\Desktop10.0\ArcToolbox\ScriptsOrdner.

blah238
quelle
13

Sie können dies erreichen, indem Sie ein Modul (dh ein Skript) in Ihr Hauptskript importieren und dessen Funktionen aufrufen. Eine einfache Demo ist in den beiden beigefügten Skripten enthalten.

    '''
Main_program.py

demonstrates how to import and call functions from another module
'''
import sys
import CallingFunctions

a_list = [1,2,3,4,5,6,7,8,9,10]
print sys.argv[0]
print CallingFunctions.func1(a_list)
print CallingFunctions.func5(a_list)
print CallingFunctions.func8(a_list)

für das Hauptprogramm und für die Funktionen, die aufgerufen werden

'''
Callingfunctions.py

imported into another program giving it access to the functions
'''

def func1(inputs=None):
  x = sum(inputs)
  return "sum some numbers: ", x
'''
more functions
'''
def func5(inputs=None):
  x_sq = 0
  for x in inputs:
    x_sq += x**2
  return "sum of squares: ", x_sq
'''
more functions
'''
def func8(inputs=None):
  return "hello from 8: ", inputs

'''
more functions
'''
if __name__ == "__main__":
  a_list = [1,2,3,4,5,6,7,8,9,10]
  inputs = "test inputs"
  a_dict = {1:[func1([1,2,3]) ],
            5:[func5([1,2,3])],
            8:[func8("inputs to 8")]}
  needed = [1,5,8]
  for akey in needed:
    if akey in a_list:
      action = a_dict[akey]
      print "\naction: ", action

Sie müssen lediglich sicherstellen, dass sich das Hauptmodul und das untergeordnete Modul im selben Ordner befinden. Sie können Parameter einfach an das untergeordnete Modul übergeben. Wenn das untergeordnete Modul Zugriff auf arcpy benötigt (vorausgesetzt, Sie verwenden Version 10 von arcmap), übergeben Sie einfach einen Verweis darauf.


quelle
6

Das Importieren und Ausführen einer Funktion ist die einfachere Möglichkeit, aber der Vollständigkeit halber gibt es auch die execfileintegrierte Funktion ( Dokumentation ), mit der Sie eine beliebige Datei im aktuellen Kontext ausführen können.

Jason Scheirer
quelle
0

Die von @JasonScheirer beschriebene Methode execfile ermöglichte es mir, meinen Code in den folgenden Code umzuwandeln , und bietet eine Lösung für mein Testproblem:

import arcpy

inputString1 = arcpy.GetParameterAsText(0)
inputString2 = arcpy.GetParameterAsText(1)

arcpy.ImportToolbox("H:/Temp/test.tbx")

# Write second Python script to an ASCII file for first parameter & execute it
f = open("H:/Temp/string1.py","w")
f.write('newFC = "H:/Temp/test.gdb/' + inputString1 + '"' + "\n")
f.write('arcpy.Copy_management("H:/Temp/test.gdb/test"' + ',newFC)')
f.close()
execfile("H:/Temp/string1.py")

# Write third Python script to an ASCII file for second parameter & execute it
f = open("H:/Temp/string2.py","w")
f.write('newFC = "H:/Temp/test.gdb/' + inputString2 + '"' + "\n")
f.write('arcpy.Copy_management("H:/Temp/test.gdb/test"' + ',newFC)')
f.close()
execfile("H:/Temp/string2.py")

Dies kann sich jedoch als umständlich erweisen, wenn es auf Skripte ohne Test angewendet wird, die viel länger dauern. Daher habe ich @ blah238s Arbeit verwendet , die @ DanPattersons Ansatz unterstützte, und den folgenden endgültigen (Test-) Code entwickelt, der genau das tut, was ich brauche.

# CopyFeaturesTool.py

import CopyFeaturesUtility
import arcpy
outputFCName = arcpy.GetParameterAsText(0)
outputFCName2 = arcpy.GetParameterAsText(1)

CopyFeaturesUtility.copyFeaturesToTempGDB("C:\\Temp\\test.gdb\\test", outputFCName)
CopyFeaturesUtility.copyFeaturesToTempGDB("C:\\Temp\\test.gdb\\test", outputFCName2)

und

# CopyFeaturesUtility.py

import arcpy
import os

def copyFeaturesToTempGDB(inputFeatures, outputName):
    """Copies the input features to a temporary file geodatabase.
    inputFeatures: The input feature class or layer.
    outputName: The name to give the output feature class."""

    tempGDB = r"C:\Temp\test.gdb"
    newFC = os.path.join(tempGDB, outputName)
    arcpy.env.overwriteOutput = True
    arcpy.Copy_management(inputFeatures, newFC)

if __name__ == '__main__':
    inputFC = r"C:\Temp\test.gdb\test"
    outputFCName = arcpy.GetParameterAsText(0)
    copyFeaturesToTempGDB(inputFC, outputFCName)
PolyGeo
quelle