Запускать скрипты Python (с параметрами) в другом скрипте Python с помощью ArcPy?

23

Обычным шаблоном кодирования, используемым в AML, было выполнение AML (с параметрами) внутри другого AML.

Приложение, которое я сейчас разрабатываю, выиграло бы от возможности запуска скрипта Python (с параметрами) в другом скрипте Python.

Тем не менее, это не так просто.

Используя ArcGIS 10, я экспериментирую с переносом «внутреннего» скрипта Python в инструмент ArcGIS, который имеет параметры. Я подумал, что было бы просто сделать так, чтобы «внешний» скрипт Python использовал arcpy.ImportToolbox для импорта набора инструментов, а затем запустил инструменты внутри него. Однако при тестировании пока все мои попытки запустить «внутренний» инструмент из «внешнего» скрипта, похоже, просто пропускают «внутренний» инструмент (ошибки не выдается).

Вот некоторый тестовый код, чтобы попытаться лучше проиллюстрировать то, что я пытаюсь описать.

Мой скрипт testinner.py:

inputString = arcpy.GetParameterAsText(0)

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

Мой скрипт 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)

Для testinner.py его инструменту нужен единственный параметр String.

Для testouter.py его инструменту нужны два параметра String

Эти два инструмента помещены в test.tbx.

Для test.gdb нужен только один пустой класс пространственных объектов, который называется test.

После того, как вы собрали все вышеперечисленное, запуск инструмента testinner с передачей строки, подобной 'abc', в качестве параметра которой должен привести к тому, что класс пространственных объектов 'test' будет скопирован в тот, который называется abc.

Но когда вы пытаетесь запустить инструмент testouter с двумя строками, такими как 'uvw' и 'xyz' в качестве параметров, инструмент testinner в testouter.py, кажется, запускается один раз, но отправляет ArcMap 10 SP2 в Vista SP2 в серьезную ошибку приложения, когда пытаясь использовать его во второй раз.

Тот же тест с использованием Windows XP SP3 и ArcGIS Desktop 10 SP2 также выдает серьезную ошибку приложения в той же точке.

PolyGeo
источник
2
Продолжая с ответом @ Dan об этом ... не думайте о .py файлах просто как о "скриптах", думайте о них как о модулях, которые вы можете повторно использовать и перерабатывать, импортируя нужные вам функции и классы из этих модулей. Абстрагируйте эти вложенные параметры GP, используя один скрипт для чтения одного набора параметров, а затем вызывайте функции в других ваших модулях по мере необходимости. Используйте трюк if name __ == '__ main ', чтобы сделать ваши модули импортируемыми и все еще используемыми автономно.
blah238
У меня есть пример Дэна, работающий для вывода: C: \ Temp \ Main_program.py ('сумма некоторых чисел:', 55) ("сумма квадратов:", 385) ("привет из 8:", [1, 2, 3 , 4, 5, 6, 7, 8, 9, 10]), но я изо всех сил пытаюсь адаптировать его к примеру с ArcPy, как я привел выше. Будем весьма благодарны за любую дополнительную помощь в том, как будет выглядеть пример ArcPy.
PolyGeo
Посмотрите ответ, который я добавил - это должно помочь объяснить вещи в контексте вашего примера лучше.
blah238
Я только что натолкнулся на отличный пост в блоге от Джейсона Парди, который предоставляет шаблон ArcPy, включающий шаблон кодирования для модулей Python, на blogs.esri.com/Dev/blogs/geoprocessing/archive/2011/07/21/…
PolyGeo
с тех пор эта ссылка была перемещена, и я полагаю, что теперь она находится здесь: blogs.esri.com/esri/arcgis/2011/08/04/pythontemplate
ndimhypervol

Ответы:

15

Вот ваш тестовый пример, модифицированный для импорта «служебного» модуля в основной скрипт и вызова функции с использованием параметров, считываемых инструментом скрипта:


CopyFeaturesTool.py - инструмент-скрипт, который считывает параметры и вызывает функцию в другом модуле.

import CopyFeaturesUtility
import arcpy

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

CopyFeaturesUtility.py - Модуль с единственной функцией copyFeaturesToTempGDB. Можно либо импортировать, либо запустить автономно. Если запустить автономно, код if __name__ == '__main__'выполняется.

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)

Я думаю, вы найдете этот модульный подход намного более эффективным и логичным, когда привыкнете к нему. Раздел « Модули» в стандартном руководстве по Python также является хорошим источником для понимания того, как работает импорт.

Для большего количества специфичных для arcpy примеров взгляните на встроенные скрипты в вашей C:\Program Files\ArcGIS\Desktop10.0\ArcToolbox\Scriptsпапке.

blah238
источник
13

Вы можете сделать это, импортировав модуль (т.е. скрипт) в ваш основной скрипт и вызвав его функции. Простая демонстрация содержится в прилагаемых двух сценариях.

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

для основной программы и для вызываемых функций

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

Вы просто должны убедиться, что основной модуль и дочерний модуль находятся в одной папке. Вы можете легко передать параметры в дочерний модуль, и если дочернему модулю нужен доступ к arcpy (при условии, что вы используете версию 10 arcmap), просто передайте ссылку на него.


источник
6

Импорт и запуск функции - более чистый способ сделать это, но для полноты картины есть также execfileвстроенная функция ( документация ), которая позволит вам запустить произвольный файл в текущем контексте.

Джейсон Шайрер
источник
0

Метод execfile, описанный @JasonScheirer, позволил мне перестроить код ниже и предоставил решение моей тестовой задачи:

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

Однако это может оказаться громоздким при применении к не тестовым скриптам, которые намного длиннее, поэтому я использовал работу @ blah238, которая одобрила подход @ DanPatterson, и предложил следующий финальный (тестовый) код, который делает именно то, что мне нужно.

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

а также

# 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
источник