Доступ к данным с помощью курсоров

Курсор – это объект доступа к данным, который может использоваться как для итерации набора строк в таблице, так и для вставки новых строк в таблицу. Курсоры могут быть трех форм: поиска, вставки и обновления. Как правило, курсоры используются для считывания существующей геометрии и записи новых геометрий.

Любой тип курсора создается соответствующей функцией arcpy.da (SearchCursor, InsertCursor или UpdateCursor) в таблице, представлении таблицы, классе объектов или векторном слое. Курсор поиска может использоваться для быстрой выборки строк. Курсор обновления может использоваться для обновления и удаления строк, тогда как курсор вставки – для вставки строк в таблицу или в класс объектов.

КурсорОбъяснение

arcpy.da.InsertCursor(in_table, field_names, {datum_transformation}, {explicit})

Вставляет строки

arcpy.da.SearchCursor(in_table, field_names, {where_clause}, {spatial_reference}, {explode_to_points}, {sql_clause}, {datum_transformation}, {spatial_filter}, {spatial_relationship}, {search_order})

Доступ только для чтения

arcpy.da.UpdateCursor(in_table, field_names, {where_clause}, {spatial_reference}, {explode_to_points}, {sql_clause}, {datum_transformation}, {explicit}, {spatial_filter}, {spatial_relationship}, {search_order})

Обновляет или удаляет строки

Функции курсора доступа к данным (arcpy.da)
Прежние версии:

В ArcGIS 10.1 добавлен модуль доступа к данным (arcpy.da). Оригинальные курсоры по-прежнему поддерживаются, однако новые курсоры arcpy.da обеспечивают значительно более высокую производительность. В большинстве случаев использование курсоров arcpy.da описывается в справочной документации. Более подробную информацию о классической модели курсоров см. в InsertCursor, SearchCursor и в разделах UpdateCursor.

Примечание:

Курсоры учитывают определяющие запросы к представлениям слоев и таблиц и выборки. Объект курсора содержит в этом случае только те строки, которые бы использовались любыми инструментами геообработки в это время.

Курсоры можно перемещать только в направлении вперед. Их нельзя передвинуть назад и выбрать строки, которые уже были выбраны. Если скрипту надо несколько раз пройти по данным, можно выбрать метод курсора reset.

Курсоры поиска и обновления можно повторять с помощью цикла for. К следующей строке можно перейти методом next для возврата следующей строки. При использовании на курсоре метода next, чтобы найти все строки в таблице, содержащей n строк, скрипт должен вызвать next N-ное количество раз. Вызов next после получения последней выбранной строки в наборе результатов возвращает исключение StopIteration.

import arcpy

cursor = arcpy.da.SearchCursor(fc, ['fieldA', 'fieldB'])
for row in cursor:
    print(row)
del cursor

Курсоры поиска и обновления также поддерживают выражения with.

import arcpy

with arcpy.da.SearchCursor(fc, ['fieldA', 'fieldB']) as cursor:
    for row in cursor:
        print(row)

Все строки, извлеченные из таблицы, выдаются в виде списка значений поля. Эти значения будут выводиться в том же порядке, как они задавались для аргумента курсора field_names. Для подтверждения порядка значений полей может также использоваться свойство курсора fields.

Объект курсора

SearchCursor, UpdateCursor и InsertCursor создают объект курсора, который может использоваться для итерации по записям. Методы объекта курсора, созданного различными функциями курсора, различаются в зависимости от типа созданного курсора.

В таблице ниже представлены методы, поддерживаемые каждым типом курсора:

Тип курсораМетод

arcpy.da.SearchCursor

reset - Сбрасывает курсор в начальное положение.

arcpy.da.InsertCursor

insertRow - Вставляет строку в таблицу.

arcpy.da.UpdateCursor

updateRow - Обновляет текущую строку.

deleteRow - Удаляет строку из таблицы

reset - Сбрасывает курсор в начальное положение.

insertRow

Курсор вставки используется для создания и вставки строк. После создания курсора для вставки списка (или набора) значений, образующих новую строку, используется метод insertRow. Любому полю в таблице, не включенному в курсор, назначается значение поля по умолчанию.

import arcpy

# Create insert cursor for table
with arcpy.da.InsertCursor("c:/base/data.gdb/roads_lut", 
                           ["roadID", "distance"]) as cursor:

    # Create 25 new rows. Set the initial row ID and distance values
    for i in range(0, 25):
        cursor.insertRow([i, 100])

updateRow

Метод updateRow используется для обновления строки в текущем положении курсора обновления. После возврата строки из объекта курсора можно при необходимости изменить строку и вызвать updateRow, передав измененную строку.

import arcpy

# Create update cursor for feature class
with arcpy.da.UpdateCursor("c:/base/data.gdb/roads",
                           ["roadtype", "distance"]) as cursor:
    for row in cursor:
        # Update the values in the distance field by multiplying 
        # the roadtype by 100. Road type is either 1, 2, 3 or 4.
        row[1] = row[0] * 100
        cursor.updateRow(row)

deleteRow

Метод deleteRow используется для удаления строки в текущем положении курсора обновления. После выбора строки вызовите deleteRow в курсоре для удаления строки.

import arcpy

# Create update cursor for feature class
with arcpy.da.UpdateCursor("c:/base/data.gdb/roads", 
                          ["roadtype"]) as cursor:
    # Delete all rows that have a roads type of 4
    for row in cursor:
        if row[0] == 4:
            cursor.deleteRow()

Доступ к значениям поля и их установка

Для каждого курсора используемые поля предоставляются списком или кортежем имен полей. При возврате строки из курсора, строка возвращается как список значений полей, соответствующих положению указателя.

В примере ниже доступ к названию штата и количеству населения осуществляется по положению.

import arcpy

fc = "c:/base/data.gdb/USA/States"

# Use SearchCursor to access state name and the population count
with arcpy.da.SearchCursor(fc, ['STATE_NAME', 'POP2000']) as cursor:
    for row in cursor:
        # Access and print the row values by index position.
        #   state name: row[0]
        #   population: row[1]
        print('{} has a population of {}'.format(row[0], row[1]))
Подсказка:

Несмотря на то, что доступ ко всем полям можно получить с помощью звездочки (*), делать это не рекомендуется. Чем больше заданных полей, тем медленнее работает курсор. Включение в список только тех полей, которые будут использоваться, улучшает производительность курсора.

Короткие и длинные значения полей возвращаются как целые числа. Значения полей с плавающей запятой и двойной точности возвращаются как числа с плавающей запятой. Типы текстовых полей возвращаются как строки. Ниже следует более подробная информация о дополнительных типах полей.

Поля идентификатора объекта

Когда вы создаете таблицу в ArcGIS, в таблицу добавляется уникальное целочисленное поле, не допускающее значения NULL, которое действует как идентификатор объекта (ID объекта). Поле Object ID объекта автоматически поддерживается в ArcGIS и гарантирует, что у каждой записи в таблице будет свой уникальный идентификатор.

Хотя все таблицы включают поле идентификатора объекта, имя поля зависит от типа данных. Токен OBJECTID@ также можно использовать в качестве сокращения вместо имени поля идентификатора объекта таблицы.

Поля геометрии

В ArcGIS тип данных geometry определяет тип геометрии объектов: точка, линия, полигон, мультиточка или мультипатч, – которые хранятся в определенной таблице. Сохраненное поле геометрии обычно, но не всегда, называется Shape.

Токены также можно использовать в качестве сокращений вместо имени поля геометрии. Токен SHAPE@, возвращающий объект геометрии может использоваться для доступа к полю геометрии класса объектов без предварительных сведений об имени поля.

Распечатайте координаты x, y класса точечных объектов, используя курсор поиска.

import arcpy

infc = "c:/data/fgdb.gdb/fc"

# Enter a for loop for each feature
with arcpy.da.SearchCursor(infc, ['OID@', 'SHAPE@']) as cursor:
    for row in cursor:
        # Print the current point's object ID and x,y coordinates
        print(f'Feature {row[0]}: {row[1][0].X}, {row[1][0].Y}')

Дополнительные токены геометрии можно использовать для доступа к конкретным сведениям о геометрии. Доступ к полной геометрии требует больше времени. Если требуются только конкретные свойства геометрии, используйте токены, чтобы предоставить быстрый доступ к свойствам геометрии. Например, SHAPE@XY возвращает набор координат x и y, представляющий центроид объекта.

Более подробно о доступе к геометрии в курсорах, см. Чтение геометрии и Запись геометрий.

Поля глобальных идентификаторов

Поля глобальных идентификаторов (Global ID и GUID) содержат строки в стиле реестра, состоящие из 36 символов, заключенных в фигурные скобки. Эти строки уникально определяют объект или запись таблицы внутри и вне базы геоданных.

В курсоре поля GUID могут воспринимать строковые значения и значения универсального уникального идентификатора (UUID). Считывание полей Global ID и GUID возвращает строку.

Для поля Global ID токен GLOBALID@ также можно использовать в качестве ярлыка вместо имени поля.

Добавьте запись в поле GUID, используя значение UUID.

import arcpy
import uuid

with arcpy.da.InsertCursor("c:/data/fgdb.gdb/fc", ['guid_field']) as cursor:
    id = uuid.uuid1()
    cursor.insertRow([id])

Добавьте запись в поле GUID, используя строку.

import arcpy

with arcpy.da.InsertCursor("c:/data/fgdb.gdb/fc", ['guid_field']) as cursor:
    id = '0345e170-2614-11eb-812d-f8b156b0d357'
    cursor.insertRow([id])

Выполните поиск записей, используя токен Global ID.

import arcpy

with arcpy.da.SearchCursor("c:/data/fgdb.gdb/fc", ["GLOBALID@"], where_clause="OWNER = 'John Doe'") as cursor:
    for row in cursor:
        print(row[0])

Поля дат

Поля дат могут хранить дату, время, дату и время или смещение.

В курсоре поле Date может работать с объектом datetime.datetime или со строковым значением. Считывание полей дат возвращает объект datetime.date.

Добавьте записи с полем Дата, используя объект datetime.

import arcpy
from datetime import datetime

with arcpy.da.InsertCursor("c:/data/fgdb.gdb/fc", ['date_field']) as cursor:
    # Datetime object created using constructor arguments
    date_value = datetime(2020, 7, 1, 12, 30)
    cursor.insertRow([date_value])

    # Datetime object created using fromisoformat method
    date_value2 = datetime.fromisoformat("2020-07-01 12:30:00")
    cursor.insertRow([date_value2])

Добавьте записи с полем Дата, используя соглашение ISO 8601 и соглашение о месяце, дне, годе, времени.

import arcpy

dates = ["2020-07-01 12:30:45",  # ISO 8601 convention
         "July 1 2020 12:30:45", # Month day year time convention
]

with arcpy.da.InsertCursor("c:/data/fgdb.gdb/fc", ['date_field']) as cursor:
    for i in dates:
        cursor.insertRow([i])

Поля даты с высокой точностью будут хранить данные с точностью до миллисекунды (1/1000 секунды), а не до секунды (1/60 минуты). Чтобы узнать больше о полях дат высокой точности, ознакомьтесь с документацией к инструменту Перенести поле дат в высокую точность.

Добавьте даты с миллисекундными данными в поле даты с высокой точностью.

Примечание:

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

impor arcpy
from datetime import datetime


dates = [datetime(2023, 8, 18, 17, 41, 13, 123456),  # datetime object
         datetime.fromisoformat("2023-08-18T17:42:15.123456"),  # datetime object from ISO 8601 string
         "2023-08-18T17:42:15.123456",  # ISO 8601 string
]

with arcpy.da.InsertCursor("c:/data/fgdb.gdb/fc", ['date_field']) as cursor:
    for i in dates:
        cursor.insertRow([i])

Поля только даты

Поле Date Only может хранить дату.

В курсоре поле Date Only может работать с объектом datetime.date или со строковым значением. Поля, содержащие только дату, также будут принимать объекты datetime.datetime, но будут отбрасывать временную часть объекта. При чтении поля, содержащего только дату, возвращается объект datetime.date.

Добавьте запись в поле Date Only, используя объект date.

import arcpy
from datetime import date

with arcpy.da.InsertCursor("c:/data/fgdb/gdb/fc", ['date_only']) as cursor:
    date_value = date(2000, 5, 26)
    cursor.insertRow([date_value])

Добавьте запись в поле Date Only, используя строковое значение.

import arcpy

with arcpy.da.InsertCursor("c:/data/fgdb/gdb/fc", ['date_only']) as cursor:
    date_value = "November 1 2015"
    cursor.insertRow([date_value])

Поля только времени

Поле Time Only может хранить время.

В курсоре поле Time Only может работать с объектом datetime.time или со строковым значением. Поля, содержащие только время, также будут принимать объекты datetime.datetime, но будут отбрасывать часть объекта, относящуюся к дате. При чтении поля, содержащего только время, возвращается объект datetime.time.

Добавьте запись в поле Time Only, используя объект datetime.datetime.

import arcpy
from datetime import time

with arcpy.da.InsertCursor("c:/data/fgdb/gdb/fc", ['time_only']) as cursor:
    date_value = time(13, 34)
    cursor.insertRow([date_value])

Добавьте запись с полем Только время, используя строковое значение.

import arcpy

with arcpy.da.InsertCursor("c:/data/fgdb/gdb/fc", ['time_only']) as cursor:
    date_value = "16:53:45"
    cursor.insertRow([date_value])

Поля сдвига метки времени

Поле Timestamp Offset может хранить дату со смещением.

В курсоре поле Timestamp Offset может работать с объектом datetime.datetime. Если объект datetime.datetime не содержит информации о часовом поясе, по умолчанию для него будет задано UTC. При считывании полей Сдвиг метки времени возвращается объект datetime.datetime.

Добавьте запись, содержащую поле Сдвиг метки времени, указав часовой пояс как UTC.

import arcpy
from datetime import datetime

with arcpy.da.InsertCursor("c:/data/fgdb/gdb/fc", ['timestamp_offset']) as cursor:
    date_value = datetime(2004, 12, 19, 16, 49, tzinfo=datetime.timezone.utc)
    cursor.insertRow([date_value])

Добавьте запись, содержащую поле Сдвиг метки времени с пользовательским смещением.

import arcpy
import datetime

tzinfo = datetime.timezone(-1 * datetime.timedelta(hours=4, minutes=15))

with arcpy.da.InsertCursor(fc, ['TIMESTAMPOFFSET']) as cursor:
    date_value = datetime.datetime(2004, 12, 19, 16, 49, tzinfo=tzinfo)
    cursor.insertRow([date_value])

Поля BLOB

Большой двоичный объект (BLOB) представляет собой некоторую часть данных, хранимую в виде длинной последовательности двоичных чисел. ArcGIS хранит в виде больших двоичных объектов (BLOB) аннотации и объекты-размеры, а также такие элементы, как изображения, мультимедиа или фрагменты кода. Курсор можно использовать для загрузки или просмотра содержимого поля BLOB.

В курсоре поля BLOB воспринимают строки, объекты bytes и объекты memoryview. Считывание полей BLOB возвращает объект memoryview.

Добавьте запись в поле BLOB, используя файл .png.

import arcpy

data = open("c:/images/image1.png", "rb").read()
with arcpy.da.InsertCursor("c:/data/fgdb.gdb/fc", ['imageblob']) as cursor:
    cursor.insertRow([data])

Прочитайте поле BLOB как объекта memoryview и запишите в файл .png.

import arcpy

with arcpy.da.SearchCursor("c:/data/fgdb.gdb/fc", ["imageblob"]) as cursor:
    memview = cursor.next()[0]
    open("c:/images/image1_copy.png", "wb").write(memview.tobytes())

Поля растра

Поле растра может хранить растровые данные в базе геоданных или вне ее.

В курсоре поиска значения из поля растра читаются как объект Raster. Курсор обновления и вставки не поддерживает поля растра.

Прочитайте поле растра и запишите в файл .tif.

import arcpy

with arcpy.da.SearchCursor("c:/data/fgdb.gdb/fc", ['imag']) as cursor:
    raster = cursor.next()[0]
    raster.save("c:/images/image.tiff")

Поля большого целого

Поле Big Integer может хранить целые числа в диапазоне от -2 53 до 253-1

Добавьте запись с полем Big Integer, используя целое число, больше чем 231.

import arcpy

with arcpy.da.InsertCursor("c:/data/fgdb.gdb/fc", ["Population"]) as cursor:
    cursor.insertRow(7654321000)

Поля аннотаций

В ArcGIS объекты аннотаций используют blob для хранения графики аннотаций в эффективной структуре. Токен ANNO@ курсора возвращает объект Annotation, который обеспечивает доступ к полной тексту графики аннотации.

Выведите свойство текстового символа для размера гало с помощью курсора поиска.

import arcpy

infc = "c:/data/fgdb.gdb/anno_fc"

# Enter a for loop for each feature
with arcpy.da.SearchCursor(infc, ['OID@','ANNO@']) as cursor:
    for row in cursor:
        # Access the current annotation feature's object and access the text graphic
        annoObj = row[1]
        cimTextGraphic = annoObj.getGraphic("V3")
        # Print a property of the text symbol
        print(f'Feature {row[0]} halo size: {cimTextGraphic.symbol.symbol.haloSize}')

Курсоры и блокировка

Курсоры вставки и обновления соблюдают блокировки таблицы, установленные приложениями ArcGIS. Блокировки предохраняют сложные процессы от изменения одной и той же таблицы одновременно. Существует два типа блокировок, общие и эксклюзивные:

  • Общая блокировка применяется в любое время к таблице или набору данных, к которым производится доступ. Несколько общих блокировок может быть создано для таблицы, но если имеется общая блокировка, то создание эксклюзивной блокировки запрещается. Отображение класса объектов и предварительный просмотр таблицы являются примерами общей блокировки.
  • Эксклюзивные блокировки применяются при внесении изменений в таблицу или класс объекта. Эксклюзивная блокировка применяется ArcGIS, например, при редактировании и сохранении класса пространственных объектов в карте, изменении схемы таблицы или при использовании курсора вставки для класса объектов в Python IDE.

Курсоры обновления и вставки не могут быть созданы для таблицы или класса объектов при наличии эксклюзивной блокировки для набора данных. Из-за эксклюзивной блокировки набора данных функции UpdateCursor или InsertCursor работать не будут. Если эти функции успешно создают курсор, то они используют эксклюзивную блокировку для набора данных так, чтобы два скрипта не могли создать курсор обновления или вставки для того же набора данных.

Курсоры поддерживают выражения with для сброса итераций и помогают снимать блокировки. Однако использование выражения del удаляет объект или заводит курсор в функцию для того, чтобы объект-курсор вышел из области применения, нужно принять во внимание настройки безопасности в случае блокировок.

В сеансе редактирования создается общая блокировка данных на время сеанса. Эксклюзивная блокировка применяется при сохранении изменений. Если существует эксклюзивная блокировка, то набор данных нельзя редактировать.