Esecuzione di script Python (con parametri) all'interno di un altro script Python con ArcPy?


23

Un modello di codifica comune utilizzato in AML era l'esecuzione di un AML (con parametri) all'interno di un altro AML.

Un'applicazione che sto attualmente sviluppando trarrebbe vantaggio dalla possibilità di eseguire uno script Python (con parametri) all'interno di un altro script Python.

Tuttavia, questo non sembra affatto semplice.

Usando ArcGIS 10, sto sperimentando il wrapping dello script Python "interno" in uno strumento ArcGIS che ha i parametri. Ho pensato che sarebbe stato semplice avere lo script Python "esterno" che utilizza arcpy.ImportToolbox per importare la toolbox e quindi eseguire gli strumenti al suo interno. Tuttavia, nel test finora tutti i miei tentativi di eseguire lo strumento "interno" dallo script "esterno" sembrano semplicemente saltare lo strumento "interno" (non viene generato alcun errore).

Ecco un po 'di codice di prova per cercare di illustrare meglio ciò che sto cercando di descrivere.

Il mio script testinner.py è:

inputString = arcpy.GetParameterAsText(0)

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

Il mio script testouter.py è:

import arcpy

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

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

arcpy.testinner_test(inputString1)

arcpy.testinner_test(inputString2)

Per testinner.py il suo strumento necessita di un singolo parametro String.

Per testouter.py il suo strumento necessita di due parametri String

I due strumenti sono collocati in un test.tbx.

Test.gdb necessita solo di una singola classe di funzioni vuota chiamata test.

Una volta assemblato quanto sopra, eseguendo lo strumento testinner con una stringa come 'abc' passata poiché il suo parametro dovrebbe comportare la copia della classe di caratteristiche 'test' in una chiamata 'abc' OK.

Ma quando provi a eseguire lo strumento testouter con due stringhe come 'uvw' e 'xyz' come parametri, lo strumento testinner in testouter.py sembra funzionare una volta, ma invia ArcMap 10 SP2 su Vista SP2 a un grave errore dell'applicazione quando cercando di usarlo la seconda volta.

Lo stesso test che utilizza Windows XP SP3 e ArcGIS Desktop 10 SP2 produce anche un errore grave dell'applicazione nello stesso punto.


2
Andando con la risposta di @ Dan su questo ... non pensare ai file .py come a "script", pensa a loro come moduli che puoi riutilizzare e riciclare importando le funzioni e le classi di cui hai bisogno da quei moduli. Estrarre quei parametri GP nidificati utilizzando uno script per leggere in un set di parametri e quindi chiamare le funzioni negli altri moduli secondo necessità. Usa il trucco if name __ == '__ main ' per rendere i tuoi moduli sia indipendenti che utilizzabili autonomamente.
blah238,

Ho l'esempio di Dan che lavora all'output: C: \ Temp \ Main_program.py ('somma alcuni numeri:', 55) ('somma dei quadrati:', 385) ('ciao da 8:', [1, 2, 3 , 4, 5, 6, 7, 8, 9, 10]) ma sto lottando per adattarlo a un esempio ArcPy come ho dato sopra. Qualsiasi ulteriore aiuto su come sarebbe un esempio di ArcPy sarebbe molto apprezzato.
PolyGeo

Vedi la risposta che ho aggiunto: dovrebbe aiutare a spiegare meglio le cose nel contesto del tuo esempio.
blah238,

Ho appena trovato un eccellente post sul blog di Jason Pardy che fornisce un modello ArcPy che incorpora il modello di codifica per i moduli Python su blogs.esri.com/Dev/blogs/geoprocessing/archive/2011/07/21/…
PolyGeo

questo collegamento da allora si è spostato e credo che ora riposi qui: blogs.esri.com/esri/arcgis/2011/08/04/pythontemplate
ndimhypervol

Risposte:


15

Ecco il tuo esempio di test modificato per importare un modulo "utility" nello script principale e chiamare una funzione utilizzando i parametri letti dallo strumento di script:


CopyFeaturesTool.py - Strumento di script che legge i parametri e chiama una funzione in un altro modulo

import CopyFeaturesUtility
import arcpy

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

CopyFeaturesUtility.py - Modulo che ha una singola funzione copyFeaturesToTempGDB. Può essere importato o eseguito autonomamente. Se eseguito in modalità autonoma, if __name__ == '__main__'viene eseguito il codice in .

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)

Penso che troverai questo approccio modulare molto più efficiente e logico una volta che ti sarai abituato. La sezione Moduli del tutorial standard di Python è anche una buona risorsa per capire come funziona l'importazione.

Per esempi più specifici di arcpy dai un'occhiata agli script integrati nella tua C:\Program Files\ArcGIS\Desktop10.0\ArcToolbox\Scriptscartella.


13

Puoi farlo importando un modulo (cioè uno script) nel tuo script principale e chiamando le sue funzioni. Una semplice demo è contenuta nei due script di accompagnamento.

    '''
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)

per il programma principale e per le funzioni che vengono chiamate

'''
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

devi solo assicurarti che il modulo principale e il modulo figlio siano nella stessa cartella. È possibile passare facilmente i parametri al modulo figlio e se il modulo figlio necessita dell'accesso ad arcpy (supponendo che si stia utilizzando la versione 10 di arcmap) è sufficiente passare un riferimento ad esso.


6

L'importazione e l'esecuzione di una funzione sono il modo più pulito per farlo, ma per completezza c'è anche la execfilefunzione integrata ( documentazione ) che ti consentirà di eseguire un file arbitrario nel contesto corrente.


0

Il metodo execfile descritto da @JasonScheirer mi ha permesso di riorganizzare il mio codice con quello di seguito e fornisce una soluzione al mio problema di test:

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")

Tuttavia, questo può rivelarsi ingombrante quando applicato a script non test che sono molto più lunghi, quindi ho usato il lavoro di @ blah238 che ha approvato l'approccio di @ DanPatterson e ho trovato il seguente codice finale (test) che fa esattamente quello di cui ho bisogno.

# 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)

e

# 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)
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.