从Python访问ArcObjects?


132

我希望能够编写一些未通过arcgisscripting或ArcPy 公开的内容。

如何从Python 访问ArcObjects


3
是否有人想过在生产环境中使用这些方法?几年前,在UC上我与一位ESRI C ++开发人员进行了交谈,他们开发了他们的大多数Python模块,他强烈反对在生产环境中使用IronPython,但这是几年前的事。
乍得·库珀

Answers:


113

下载并安装comtypes *,将SnippetsMark Cederholm 的模块放在PYTHONPATH中,一切就绪

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

有关背景信息,请参阅Mark Cederholm 在UberPyGeeks上的“在Python中使用ArcObjects”演示。对于VBA和C ++开发人员而言,有单独的观点。他们使用Visual Studio(可以使用Express还是可以的)和Windows SDK,但这不是必需的,仅ArcGIS,Python和comtypes就足够了。

获取代码片段模块

* 请注意,对于10.1+,您需要automation.py在comtypes模块中进行一些小的更改。请参见10.1中的ArcObjects + comtypes


下一步

...或:大脑变得蛇行?看一下C#代码示例,您会眼前一亮,然后尝试尝试一下,就像只是无法像起重机一样思考?看这里:


10
这个话题已经引起我的注意,似乎存在一些误解。您不需要Visual Studio或MIDL编译器即可在Python中使用ArcObjects。您需要的只是comtypes包。我的演讲包括使用Python创建COM组件的高级练习,但这是针对UberPyGeeks的。snippets.py文件包含您需要的所有示例。

1
@Mark,非常感谢您的纠正。需要说明的是:在上述配方中,只要已经安装了ctypes,就可以删除步骤1、3、4 。
马特·威尔基2011年

2
是的 在实验室进行了测试。您只需要安装comtypes。
2012年

@RK,太好了!感谢您的验证并提供最新答案。
马特·威尔基

1
片段模块在此处可重装为可安装的ao模块:github.com/maphew/arcplus/tree/master/arcplus/ao(已更新为10.3,有关10.2,请参见文件的先前版本)。一旦我清除了一些错误,就会更新主要答案。
马特·威尔基

32

是的,Matt Wilkie上面提到的Mark Cederholm的演讲是一个很好的起点。Matt提出的配方/代码无疑是一种巧妙的方法,并且可能是解决问题的最佳方法。不过,我想提一下我在ArcGIS 10.0中使用的蛮力方法。我有几种以这种方式运行的自动化脚本(独立的,在应用程序边界之外),它们运行良好。但是,如果需要考虑最大速度,则可以采用Matt的解决方案并完成它。

我使用comtypes包强制包装所有ArcObjects库(.olb)。然后,Python可以访问所有ArcObjects。我通过一个ESRI论坛帖子从Frank Perks获得了包装代码。我有自己的代码,基本上执行了相同的操作,但是它肿且仅具有功能,而他的代码更漂亮。所以:

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)

然后,完全是马克·塞德霍尔姆的演讲:

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

而已。您应该具有对ArcObjects的完全访问权限,从pRef对象(即AppRef对象上的IApplication)开始。以我的经验,第一次运行时对ArcObjects库的包装不会令人讨厌,并且对于后续运行,也不会发生包装。库已经包装和编译,因此速度更快。

补充: 随之而来的是一个很大的警告。这里给出的NewObj函数假定Python脚本正在进程内运行。如果不是,此函数将在Python进程(即进程外)中创建对象,并且对象引用将是错误的。要从外部Python脚本创建过程中对象,应使用IObjectFactory。有关更多信息,请参见此stackexchange 帖子中的 Kirk Kuykendall的评论和提示。


1
这种方法的好处是不需要安装Visual Studio,如果您唯一要做的就是注册com对象,则这是相当沉重的。如果我知道这种纯python方法,那么我可能从未尝试过Cederholm的路线。;-)
马特·威尔基2011年

1
我扩大这个概念有点在这个答案,使得进口和包装类型库一个步骤:gis.stackexchange.com/questions/5017/...
blah238

20

如何从python访问arcobjects?

如果您要寻找的是C ++ Arcobjects代码中存在的特定功能,那么最好的选择是创建C ++方法来调用它们。

有很多方法可以从python访问C ++方法,许多人使用诸如SWIG之类的工具从C ++方法签名自动生成python类。根据我的经验,这些自动生成的API在传递非本机C ++类型(int,float)时会变得非常讨厌,并且它们从来都不是“ pythonic ”的。

我推荐的解决方案是使用ctypes API。一个很棒的教程在这里:http : //python.net/crew/theller/ctypes/tutorial.html

基本步骤是:

  1. 用C ++编写一些核心逻辑,您认为python性能可能是一个问题
  2. 使用任何系统编译器(nmake,make等)将目标文件中的核心逻辑(在这种情况下,使用ArcObject C ++ API方法调用)编译为共享(.so)或动态库(.dll)。
  3. 在python类和C ++方法签名之间编写ctypes映射[SWIG尝试自动执行此操作,但这很容易,即使使用疯狂的对象类型也是如此]
  4. 将已编译的库导入到python程序中,并像其他任何python类一样使用绑定的类/方法绑定!

这可能是从python内部引用C / C ++代码的更通用的方法,从长远来看,如果不必处理COM对象,它可能会变得更加简单。它还将允许所有特定于系统的功能驻留在链接库对象的编译中(因此python将不是特定于系统/ python实现的)。


3
这是与ArcObjects进行交互的最佳方法。使用原型对于原型制作非常有用,但是编写您自己的C扩展将导致良好的Pythonic设计(因为您必须考虑它)和更好的性能,因为您不会越过C ++ / Python对象障碍。尽管出于实际目的,这更难于设计/开发/调试,所以快捷便不在了。
詹森·谢里尔

18

另一个选择是将Python用于.NET-设置非常容易,并且可以与包括ArcObjects在内的任何.NET DLL一起使用。

我在处理过程中没有遇到过任何问题,因此打开ArcMap实例并添加和操作图层对我来说效果很好。

唯一的要求是一个包含Python for .NET库的文件夹和一个标准的Python安装。

更多详细信息和示例脚本在此处。示例脚本也可以直接在http://gist.github.com/923954上看到。

不幸的是,尽管这在本地开发计算机上没有问题,但将其部署到其他地方则需要安装ArcObjects SDK和Visual Studio(包括免费的Express版本)。请参阅部署ArcObject .NET DLL


食谱清晰,明了且讲究。感谢Geographika!我建议您在回答中包含最少的脚本片段,以便在您的网站进行装修的情况下,回答可以独立存在。
马特·威尔基2011年

1
这正是我在此旧博客文章(gissolved.blogspot.com/2009/06/python-toolbox-3-pythonnet.html)中所做的工作,它可以按预期工作,但请确保返回您的Python脚本可以理解的结果(字符串,数字)或无效)。
塞缪尔


5

在其他答案中没有提到的一种方法是使用与arcpy库本身使用的方法相同的方法。例如,在C:\ Program Files \ ArcGIS \ Desktop10.0 \ arcpy \ arcpy \ cartography.py中,我们看到Python使用一些fixargs和对象转换函数调用ArcObjects工具。

我不希望在此处发布多少代码,因为代码显示“ TRADE SECRETS:ESRI专有和机密”;但您也可以在网络上的其他地方找到它。无论如何,这看起来是调用函数的相对简单的方法,例如SimplifyBuilding_cartography()无需安装comtypes或任何其他额外的库。

编辑:

请参阅下面的Jason评论。听起来像做上面的事情不会买很多东西。


我也注意到了,但似乎也太多了。
blah238 2013年

1
它不是在调用完全公开的arcobjects集。
詹森·谢里尔

@JasonScheirer,尽管如此,它显然允许比直接arcpy API更大程度的访问ArcObjects(我认为),并且它的优点是不需要安装其他库。如果您正在开发供其他人使用的工具,则后者可能很重要。我想知道您可以通过这种方法访问的全部内容,对于某些目的,这可能就足够了。(我现在无法检查-我不在公司的LAN上。)
LarsH 2013年

1
我可以向您保证事实并非如此。我开发了很多。
詹森·谢里尔

1
你不能。在这种情况下,“ ArcObject”有点用词不当。无法访问基础对象,也没有COM绑定将所有ArcObjects暴露在arcgisscripting / arcpy中的任何位置。
詹森·谢里尔
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.