Zugriff auf ArcObjects über Python?


132

Ich möchte in der Lage sein, einige Dinge zu arcgisscriptingskripten , die nicht über oder ArcPy verfügbar gemacht werden.

Wie greife ich von Python aus auf ArcObjects zu ?


3
Hat jemand Gedanken zur Verwendung dieser Methoden in Produktionsumgebungen? Vor ein paar Jahren sprach ich an der UC mit einem der ESRI C ++ - Entwickler, der die meisten seiner Python-Module schreibt, und er war entschieden dagegen, IronPython in einer Produktionsumgebung einzusetzen - aber das war vor ein paar Jahren.
Chad Cooper

Antworten:


113

Laden Sie comtypes * herunter und installieren Sie es , setzen Sie das SnippetsModul von Mark Cederholm in PYTHONPATH ein und schon sind Sie fertig.

from snippets102 import GetLibPath, InitStandalone
from comtypes.client import GetModule, CreateObject
m = GetModule(GetLibPath() + "esriGeometry.olb")
InitStandalone()
p = CreateObject(m.Point, interface=m.IPoint)
p.PutCoords(2,3)
print p.X, p.Y

Hintergrundinformationen finden Sie in den Präsentationen von Mark Cederholm für UberPyGeeks zum Thema "Verwenden von ArcObjects in Python" . Für VBA- und C ++ - Entwicklerperspektiven gibt es separate. Sie verwenden Visual Studio (ja, Express ist in Ordnung) und das Windows SDK , aber diese sind nicht erforderlich, nur ArcGIS, Python und Comtypes sind ausreichend.

Abrufen des Snippets-Moduls

* Hinweis für 10.1+ müssen Sie automation.pyim comtypes-Modul eine kleine Änderung vornehmen. Siehe ArcObjects + comtypes unter 10.1 .


Nächste Schritte

... oder: Gehirn schlapp gemacht ? Wenn Sie sich die C # -Codebeispiele ansehen, schwimmen Ihre Augen und versuchen Sie, wie Sie vielleicht einfach nicht wie ein Kran denken können ? Schau hier:


10
Dieser Thread wurde auf mich aufmerksam gemacht, und es scheint, dass einige Missverständnisse im Umlauf sind. Sie benötigen weder Visual Studio noch den MIDL-Compiler, um ArcObjects in Python zu verwenden. Alles was Sie brauchen ist das comtypes-Paket. Meine Präsentation enthielt eine erweiterte Übung zum Erstellen einer COM-Komponente mit Python, die jedoch für UberPyGeeks gedacht war. Die Datei snippets.py enthält alle erforderlichen Beispiele.

1
@Mark, vielen Dank für die Korrektur. Um es klar auszudrücken : Im obigen Rezept kann man die Schritte 1,3,4 entfernen, solange ctypes bereits installiert ist.
Matt Wilkie

2
Ja. Im Labor getestet. Sie müssen nur die comtypes installieren.
RK

@RK, großartig! Vielen Dank für die Überprüfung und Aktualisierung der Antwort.
Matt Wilkie

1
Neufassung des Snippets-Moduls als installierbares ua- Modul hier: github.com/maphew/arcplus/tree/master/arcplus/ao (aktualisiert für 10.3, siehe vorherige Versionen der Datei für 10.2). Aktualisiert die Hauptantwort, sobald einige Fehler beseitigt sind.
Matt Wilkie

32

Ja, Mark Cederholms Präsentation, die Matt Wilkie oben erwähnt, ist ein großartiger Anfang. Das Rezept / der Code, den Matt vorlegt, ist mit Sicherheit ein geschickter und wahrscheinlich der beste Weg, um Dinge zu erledigen. Ich wollte jedoch die ziemlich brachiale Methode erwähnen, die ich in ArcGIS 10.0 verwende. Ich habe mehrere Automatisierungsskripte (eigenständig, außerhalb der Anwendungsgrenzen), die ich auf diese Weise ausführe, und sie funktionieren einwandfrei. Wenn es jedoch um die maximale Geschwindigkeit geht, können Sie sich einfach für Matts Lösung entscheiden und damit fertig werden.

Ich verwende das comtypes-Paket, um das Umbrechen aller ArcObjects-Bibliotheken (.olb) zu erzwingen. Dann hat Python Zugriff auf alle ArcObjects. Ich habe den Code von Frank Perks über ein ESRI-Forum erhalten . Ich hatte meinen eigenen Code, der im Wesentlichen dasselbe tat, aber er war aufgebläht und nur funktional, während sein Code viel hübscher ist. Damit:

import sys, os
if '[path to your Python script/module directory]' not in sys.path:
    sys.path.append('[path to your Python script/module directory]')

import comtypes
#force wrapping of all ArcObjects libraries (OLBs)
import comtypes.client
# change com_dir to whatever it is for you
com_dir = r'C:\Program Files (x86)\ArcGIS\Desktop10.0\com'
coms = [os.path.join(com_dir, x) for x in os.listdir(com_dir) if os.path.splitext(x)[1].upper() == '.OLB']
map(comtypes.client.GetModule, coms)

Dann, so ziemlich direkt aus Mark Cederholms Präsentation:

import comtypes.gen.esriFramework

pApp = GetApp()

def GetApp():
    """Get a hook into the current session of ArcMap"""
    pAppROT = NewObj(esriFramework.AppROT, esriFramework.IAppROT)
    iCount = pAppROT.Count

    if iCount == 0:
        print 'No ArcGIS application currently running.  Terminating ...'
        return None
    for i in range(iCount):
        pApp = pAppROT.Item(i)  #returns IApplication on AppRef
        if pApp.Name == 'ArcMap':
            return pApp
    print 'No ArcMap session is running at this time.'
    return None

def NewObj(MyClass, MyInterface):
    """Creates a new comtypes POINTER object where\n\
    MyClass is the class to be instantiated,\n\
    MyInterface is the interface to be assigned"""
    from comtypes.client import CreateObject
    try:
        ptr = CreateObject(MyClass, interface=MyInterface)
        return ptr
    except:
        return None

Das ist es. Sie sollten vollen Zugriff auf ArcObjects haben, beginnend mit dem pApp-Objekt, das IApplication für das AppRef-Objekt ist. Nach meiner Erfahrung ist das Umschließen der ArcObjects-Bibliotheken beim ersten Durchlauf nicht unangenehm langsam, und bei nachfolgenden Durchläufen erfolgt das Umschließen nicht. Die Bibliotheken sind bereits verpackt und kompiliert, so dass die Dinge viel schneller laufen.

Hinzugefügt: Es gibt eine große Vorsicht, die damit einhergeht. Die hier angegebene NewObj-Funktion setzt voraus, dass das Python-Skript in-process ausgeführt wird. Wenn nicht, erstellt diese Funktion Objekte im Python-Prozess (dh außerhalb des Prozesses), und die Objektreferenzen sind falsch. Um in einem Prozess Objekte aus einem externen Python-Skript zu erstellen, sollten Sie IObjectFactory verwenden. Weitere Informationen finden Sie in den Kommentaren und Tipps von Kirk Kuykendall in diesem Stapelwechsel-Beitrag .


1
Das Schöne an diesem Ansatz ist, dass Visual Studio nicht installiert werden muss. Dies ist ziemlich schwer, wenn Sie nur die COM-Objekte registrieren müssen. Wenn ich über diese reine Python-Methode Bescheid gewusst hätte, hätte ich wahrscheinlich nie Cederholms Route ausprobiert. ;-)
matt wilkie

1
Ich habe dieses Konzept in dieser Antwort ein wenig erweitert und den Import und das Umschließen
blah238

20

Wie greife ich mit Python auf ArcObjects zu?

Wenn Sie nach einer bestimmten Funktionalität suchen, die vorhanden ist und im C ++ - Arcobjects-Code enthalten ist, sollten Sie am besten C ++ - Methoden erstellen, um sie aufzurufen. Erstellen Sie anschließend einen Python-Wrapper, um auf diese C ++ - Methoden zuzugreifen.

Es gibt eine ganze Reihe von Möglichkeiten, über Python auf C ++ - Methoden zuzugreifen, und viele Leute verwenden dazu ein Tool wie SWIG , um die Python-Klassen automatisch aus den C ++ - Methodensignaturen zu generieren. Ich habe die Erfahrung gemacht, dass diese automatisch generierten APIs beim Übergeben nicht nativer C ++ - Typen (int, floats) ziemlich unangenehm werden und nie sehr " pythonisch " sind.

Meine empfohlene Lösung wäre die Verwendung der ctypes-API. Ein großartiges Tutorial finden Sie hier: http://python.net/crew/theller/ctypes/tutorial.html

Die grundlegenden Schritte sind:

  1. Schreiben Sie einige Ihrer Kernlogiken in C ++, von denen Sie glauben, dass die Python-Leistung ein Problem sein könnte
  2. Kompilieren Sie diese Kernlogik (in diesem Fall mithilfe der ArcObject C ++ - API-Methodenaufrufe) aus Objektdateien in eine freigegebene (.so) oder dynamische Bibliothek (.dll) mit einem beliebigen Systemcompiler (nmake, make usw.).
  3. Schreiben Sie eine ctypes-Zuordnung zwischen der Python-Klasse und der C ++ - Methodensignatur. [SWIG versucht dies zu automatisieren, aber es ist einfach, auch wenn verrückte Objekttypen verwendet werden.]
  4. Importieren Sie die kompilierte Bibliothek in Ihr Python-Programm und verwenden Sie die gebundenen Klassen- / Methodenbindungen wie jede andere Python-Klasse!

Dies ist wahrscheinlich eine allgemeinere Methode, um C / C ++ - Code aus Python heraus zu referenzieren. Auf lange Sicht wird dies wahrscheinlich viel einfacher, wenn Sie sich nicht mit COM-Objekten befassen müssen. Es ermöglicht auch, dass alle systemspezifischen Funktionen in der Kompilierung des verknüpften Bibliotheksobjekts enthalten sind (sodass der Python nicht system- / python-spezifisch ist).


3
Dies ist bei weitem die beste Methode zur Interaktion mit ArcObjects. Die Verwendung von Comtypes ist ideal für das Prototyping, aber das Schreiben einer eigenen C-Erweiterung führt zu einem guten Pythonic-Design (weil Sie darüber nachdenken müssen) und einer besseren Leistung, da Sie die C ++ / Python-Objektgrenze nicht so häufig überschreiten. Obwohl dies aus praktischen Gründen schwieriger zu entwerfen, zu entwickeln und zu debuggen ist, geht der Schnelle und Schmutzige aus dem Fenster.
Jason Scheirer

18

Eine andere Option ist die Verwendung von Python für .NET. Dies ist sehr einfach einzurichten und kann mit allen .NET-DLLs einschließlich ArcObjects verwendet werden.

Ich habe keine Probleme mit In-Process-Objekten festgestellt. Das Öffnen einer Instanz von ArcMap und das Hinzufügen und Bearbeiten von Layern hat für mich problemlos funktioniert.

Die einzigen Voraussetzungen sind ein Ordner mit der Python for .NET-Bibliothek und eine Standard-Python-Installation.

Weitere Details und Beispielskript hier . Das Beispielskript kann auch direkt unter http://gist.github.com/923954 eingesehen werden

Obwohl dies auf einem lokalen Entwicklungscomputer problemlos funktioniert, müssen für die Bereitstellung an einem anderen Ort das ArcObjects SDK und Visual Studio (einschließlich der kostenlosen Express-Edition) installiert sein. Siehe Bereitstellen von ArcObject .NET-DLLs


Das Rezept ist klar, klar und gut präsentiert. Vielen Dank Geographika! Ich empfehle Ihnen, ein minimales Skript-Snippet in Ihre Antwort aufzunehmen, damit die Antwort für den Fall, dass Ihre Site renoviert wird, für sich alleine stehen kann.
Matt Wilkie

1
Genau das habe ich in diesem alten Blogpost getan ( gissolved.blogspot.com/2009/06/python-toolbox-3-pythonnet.html ) und es funktioniert wie erwartet, aber stellen Sie sicher, dass Ergebnisse zurückgegeben werden, die Ihr Python-Skript versteht (Zeichenfolgen, Zahlen) oder nichtig).
Samuel


5

Ein Ansatz, der in den anderen Antworten nicht erwähnt wird, besteht darin, die gleichen Methoden zu verwenden, die die Arcpy-Bibliotheken selbst verwenden. In C: \ Programme \ ArcGIS \ Desktop10.0 \ arcpy \ arcpy \ cartography.py wird beispielsweise Python beim Aufrufen von ArcObjects-Tools mit einigen Fixargs und Objektkonvertierungsfunktionen angezeigt.

Ich weiß nicht, wie viel es in Ordnung ist, hier darüber zu posten, da der Code "TRADE SECRETS: ESRI PROPRIETARY AND CONFIDENTIAL" lautet. Sie finden es aber auch an anderer Stelle im Internet. SimplifyBuilding_cartography()Auf jeden Fall scheint dies eine relativ einfache Möglichkeit zu sein, Funktionen aufzurufen, ohne comtypes oder andere zusätzliche Bibliotheken zu installieren.

Bearbeiten:

Siehe Jasons Kommentare unten. Klingt so, als würde Ihnen das oben Genannte nicht viel bringen.


Mir ist auch aufgefallen, scheint aber zu viel Voodoo zu sein.
blah238

1
Es wird kein vollständig belichteter Satz von ArcObjects aufgerufen.
Jason Scheirer

@JasonScheirer, wie auch immer, es erlaubt anscheinend einen höheren Grad an Zugriff auf ArcObjects (glaube ich) als die direkte ArcPy-API, und es hat den Vorteil, dass keine Installation einer anderen Bibliothek erforderlich ist. Letzteres kann wichtig sein, wenn Sie Tools entwickeln, die andere Benutzer verwenden können. Ich würde gerne wissen, auf was Sie mit dieser Methode in vollem Umfang zugreifen können - es könnte für bestimmte Zwecke ausreichen. (Ich kann jetzt allerdings nicht
nachsehen

1
Ich kann Ihnen versichern, dass dies nicht der Fall ist. Ich habe viel davon entwickelt.
Jason Scheirer

1
Du kannst nicht. "ArcObject" ist in diesem Fall eine falsche Bezeichnung. Es gibt keine Möglichkeit, zu den zugrunde liegenden Objekten zu gelangen, und es gibt keine COM-Bindung, durch die alle ArcObjects in arcgisscripting / arcpy verfügbar gemacht werden.
Jason Scheirer
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.