Truy cập ArcObjects từ Python?


132

Tôi muốn có thể viết kịch bản một số thứ không được tiết lộ qua arcgisscriptinghoặc ArcPy.

Làm cách nào để tôi truy cập ArcObjects từ Python?


3
Bất cứ ai cũng có suy nghĩ về việc sử dụng các phương pháp này trong môi trường sản xuất? Vài năm trước tại UC tôi đã nói chuyện với một trong những nhà phát triển ESRI C ++, người viết hầu hết các mô-đun Python của họ và anh ấy đã mạnh mẽ chống lại việc sử dụng IronPython trong môi trường sản xuất - nhưng đó là vài năm trước.
Chad Cooper

Câu trả lời:


113

Tải xuống và cài đặt comtypes *, đặt Snippetsmô-đun từ Mark Cederholm trong PYTHONPATH và bạn đã hoàn tất.

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

Để biết thông tin chi tiết, hãy xem các bài thuyết trình của Mark Cederholm cho UberPyGeek về "Sử dụng ArcObjects trong Python" . Có những cái riêng cho quan điểm của nhà phát triển VBA và C ++. Họ sử dụng Visual Studio (có Express là ok) và SDK Windows , nhưng những thứ này không bắt buộc, chỉ cần ArcGIS, Python và comtypes là đủ.

Lấy mô-đun Snippets

* Lưu ý cho 10.1+ bạn cần thực hiện một thay đổi nhỏ automation.pytrong mô-đun comtypes. Xem ArcObjects + comtypes tại 10.1 .


Bước tiếp theo

... Hoặc: não biến mất ? Nhìn vào các ví dụ mã c # làm cho mắt bạn bơi, và cố gắng như bạn có thể không nghĩ giống như một con sếu ? Nhìn đây:


10
Chủ đề này đã được đưa đến sự chú ý của tôi, và dường như có một số quan niệm sai lầm trôi nổi xung quanh. Bạn KHÔNG cần Visual Studio hoặc trình biên dịch MIDL để sử dụng ArcObjects trong Python; tất cả những gì bạn cần là gói comtypes. Bài thuyết trình của tôi bao gồm một bài tập nâng cao trong việc tạo thành phần COM bằng Python, nhưng điều đó có nghĩa là cho UberPyGeek. Tệp snippets.py chứa tất cả các ví dụ bạn cần.

1
@Mark, cảm ơn rất nhiều vì đã sửa. Để rõ ràng: trong công thức trên, người ta có thể loại bỏ các bước 1,3,4 miễn là ctypes đã được cài đặt?
matt wilkie

2
Vâng. Đã thử nó tại phòng thí nghiệm. Bạn chỉ cần cài đặt comtypes.
RK

@RK, tuyệt! Cảm ơn đã xác minh và đưa câu trả lời cập nhật.
matt wilkie

1
Mô-đun đoạn trích được gọi lại là mô-đun ao có thể cài đặt tại đây: github.com/maphew/arcplus/tree/master/arcplus/ao (cập nhật cho 10.3, xem các phiên bản trước của tệp cho 10.2). Sẽ cập nhật câu trả lời chính khi tôi nhận được một số lỗi.
matt wilkie

32

Vâng, bài thuyết trình của Mark Cederholm mà Matt Wilkie đề cập ở trên là một nơi tuyệt vời để bắt đầu. Công thức / mã mà Matt trình bày chắc chắn là một cách khéo léo và có lẽ là cách tốt nhất để đi về mọi thứ. Mặc dù vậy, tôi muốn đề cập đến phương pháp khá mạnh mẽ mà tôi đang sử dụng trong ArcGIS 10.0. Tôi có một số tập lệnh tự động hóa (độc lập, bên ngoài ranh giới ứng dụng) mà tôi chạy theo cách này và chúng hoạt động tốt. Tuy nhiên, nếu tốc độ tối đa là một mối quan tâm, bạn có thể chỉ cần đi với giải pháp của Matt và được thực hiện với nó.

Tôi sử dụng gói comtypes để buộc gói tất cả các thư viện ArcObjects (.olb). Sau đó, Python có quyền truy cập vào tất cả ArcObjects. Tôi đã nhận được mã gói từ Frank Perks thông qua một bài đăng trên diễn đàn ESRI . Tôi đã có mã riêng của mình về cơ bản đã làm điều tương tự, nhưng nó bị bồng bềnh và chỉ đơn thuần là chức năng, trong khi mã của nó đẹp hơn nhiều. Vì thế:

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)

Sau đó, khá nhiều từ bài thuyết trình của Mark Cederholm:

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

Đó là nó. Bạn nên có quyền truy cập đầy đủ vào ArcObjects bắt đầu với đối tượng pApp là ứng dụng IApplication trên đối tượng AppRef. Theo kinh nghiệm của tôi, việc gói các thư viện ArcObjects trong lần chạy đầu tiên không bị chậm lại một cách khó chịu và đối với các lần chạy tiếp theo, việc gói này không xảy ra. Các thư viện đã được gói và biên dịch, vì vậy mọi thứ nhanh hơn nhiều.

Đã thêm: Có một sự thận trọng lớn đi kèm với điều này. Hàm NewObj được cung cấp ở đây giả sử tập lệnh Python đang được chạy trong quá trình. Nếu không, hàm này sẽ tạo các đối tượng trong quy trình Python (nghĩa là hết quy trình) và các tham chiếu đối tượng sẽ sai. Để tạo các đối tượng xử lý từ tập lệnh Python bên ngoài, bạn nên sử dụng IObjectFactory. Xem ý kiến ​​và lời khuyên của Kirk Kuykendall trong bài đăng trên stackexchange này để biết thêm thông tin.


1
Điều thú vị về cách tiếp cận này là nó không yêu cầu cài đặt Visual Studio, điều này khá nặng nề nếu điều duy nhất bạn sẽ làm với nó là đăng ký các đối tượng com. Nếu tôi biết về phương pháp trăn thuần túy này, có lẽ tôi chưa bao giờ thử tuyến đường của Cederholm. ;-)
matt wilkie

1
Tôi đã mở rộng khái niệm này một chút trong câu trả lời này, làm cho việc nhập và gói các thư viện loại thành một quy trình một bước: gis.stackexchange.com/questions/5017/ Lỗi
blah238

20

Làm cách nào để truy cập arcobjects từ python?

Nếu những gì bạn đang tìm kiếm là chức năng cụ thể tồn tại và nằm trong mã C ++ Arcobjects, thì cách tốt nhất của bạn là tạo các phương thức C ++ để gọi chúng .... và sau đó tạo một trình bao bọc python để truy cập các phương thức C ++ đó.

Có khá nhiều cách để truy cập các phương thức C ++ từ python và rất nhiều người sử dụng một công cụ như SWIG để tự động tạo các lớp python từ chữ ký của phương thức C ++. Theo kinh nghiệm của tôi, các API được tạo tự động này trở nên khá khó chịu khi truyền các loại C ++ không bản địa (int, float) và không bao giờ rất ' pythonic '.

Giải pháp được đề xuất của tôi sẽ là sử dụng API ctypes. Một hướng dẫn tuyệt vời có tại đây: http://python.net/crew/theller/ctypes/tutorial.html

Các bước cơ bản là:

  1. viết một số logic cốt lõi của bạn trong C ++, những cái mà bạn tin rằng hiệu suất của python có thể là một vấn đề
  2. Biên dịch logic lõi đó (trong trường hợp này bằng cách sử dụng các cuộc gọi phương thức API ArcObject C ++) từ các tệp đối tượng vào một thư viện chia sẻ (.so) hoặc động (bằng cách sử dụng bất kỳ trình biên dịch hệ thống nào (nmake, make, v.v.)
  3. Viết ánh xạ ctypes giữa lớp python và chữ ký phương thức C ++ [SWIG cố gắng tự động hóa việc này, nhưng thật dễ dàng, ngay cả khi sử dụng các loại đối tượng điên]
  4. Nhập thư viện đã biên dịch vào chương trình python của bạn và sử dụng các ràng buộc của lớp / phương thức bị ràng buộc như bất kỳ lớp python nào khác!

Đây có lẽ là cách tổng quát hơn để tham chiếu mã C / C ++ từ bên trong python, về lâu dài có lẽ sẽ đơn giản hơn nhiều nếu bạn không phải xử lý các đối tượng COM. Nó cũng sẽ cho phép tất cả các chức năng cụ thể của hệ thống nằm trong quá trình biên dịch đối tượng thư viện được liên kết (vì vậy python sẽ không được triển khai hệ thống / python cụ thể).


3
Đây là phương pháp tốt nhất để tương tác với ArcObjects. Việc sử dụng comtypes rất tốt cho tạo mẫu nhưng viết phần mở rộng C của riêng bạn sẽ mang lại một thiết kế Pythonic tốt (vì bạn phải suy nghĩ về nó) và hiệu suất tốt hơn vì bạn không vượt qua rào cản đối tượng C ++ / Python nhiều. Mặc dù cho các mục đích thực tế, điều này khó hơn để thiết kế / phát triển / gỡ lỗi để nhanh chóng và bẩn thỉu ra khỏi cửa sổ.
Jason Scheirer

18

Một tùy chọn khác là sử dụng Python cho .NET - điều này rất dễ thiết lập và có thể hoạt động với bất kỳ DLL .NET nào kể cả ArcObjects.

Tôi đã không gặp phải bất kỳ vấn đề nào với các lỗi trong quá trình và mở ra một phiên bản ArcMap và thêm và thao tác các lớp hoạt động tốt với tôi.

Các yêu cầu duy nhất là một thư mục chứa thư viện Python cho .NET và cài đặt Python chuẩn.

Thêm chi tiết và kịch bản mẫu ở đây . Tập lệnh mẫu cũng có thể được xem trực tiếp tại http://gist.github.com/923954

Thật không may, trong khi điều này hoạt động mà không gặp sự cố trên máy phát triển cục bộ, thì việc triển khai nó ở nơi khác yêu cầu SDK ArcObjects và Visual Studio (bao gồm cả phiên bản Express miễn phí) được cài đặt. Xem Triển khai các tệp .NET ArcObject .NET


Các công thức rõ ràng, sáng suốt và trình bày tốt. Cảm ơn Geographika! Tôi khuyến khích bạn bao gồm một đoạn mã tối thiểu trong câu trả lời của bạn, để trong trường hợp trang web của bạn trải qua quá trình cải tạo, câu trả lời có thể tự đứng vững.
matt wilkie

1
Đó chính xác là những gì tôi đã làm trong blogpost cũ này ( gissolve.blogspot.com/2009/06/python-toolbox-3-pythonnet.html ) và nó hoạt động như mong đợi nhưng đảm bảo trả về kết quả mà tập lệnh Python của bạn hiểu được (chuỗi, số hoặc khoảng trống).
Samuel


5

Một cách tiếp cận tôi không thấy được đề cập trong các câu trả lời khác là sử dụng các phương thức tương tự mà các thư viện arcpy sử dụng. Ví dụ: trong C: \ Program Files \ ArcGIS \ Desktop10.0 \ arcpy \ arcpy \ cartography.py, chúng tôi thấy Python gọi các công cụ ArcObjects bằng cách sử dụng một số chức năng sửa lỗi và chuyển đổi đối tượng.

Tôi không biết bao nhiêu là ổn để đăng về nó ở đây, vì đoạn mã có nội dung "BÍ MẬT THƯƠNG MẠI: SỞ HỮU VÀ BÍ MẬT ESRI"; nhưng bạn cũng sẽ tìm thấy nó ở nơi khác trên web. Dù sao, đây có vẻ là một cách tương đối dễ dàng để gọi các hàm như SimplifyBuilding_cartography()không cần cài đặt comtypes hoặc bất kỳ thư viện bổ sung nào khác.

Biên tập:

Xem bình luận của Jason bên dưới. Âm thanh như làm ở trên sẽ không mua cho bạn nhiều.


Tôi cũng nhận thấy điều đó, có vẻ như quá nhiều voodoo.
blah238

1
Nó không gọi là một bộ arcobject được phơi bày đầy đủ.
Jason Scheirer

@JasonScheirer, vì có thể, rõ ràng nó cho phép mức độ truy cập vào ArcObjects (tôi nghĩ) lớn hơn so với API arcpy thẳng và nó có lợi thế là không cần cài đặt thư viện khác. Cái sau có thể quan trọng nếu bạn đang phát triển các công cụ cho người khác sử dụng. Tôi muốn biết toàn bộ phạm vi của những gì bạn có thể truy cập thông qua phương pháp này - nó có thể là đủ cho các mục đích nhất định. (Tôi không thể kiểm tra ngay bây giờ - Tôi không thuộc mạng LAN của công ty.)
LarsH

1
Tôi có thể đảm bảo với bạn rằng thực tế không phải vậy. Tôi đã phát triển nhiều về nó.
Jason Scheirer

1
Bạn không thể. "ArcObject" là một chút sai lầm trong trường hợp này. Không có cách nào để đến các đối tượng cơ bản và không có ràng buộc COM nào phơi bày tất cả các ArcObject ở bất cứ đâu trong arcgisscripting / arcpy.
Jason Scheirer
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.