Accès aux données à l'aide de curseurs

Un curseur est un objet d'accès aux données permettant d'explorer par itération un ensemble de lignes d'une table ou d'insérer de nouvelles lignes dans une table. Les curseurs peuvent prendre trois formes : recherche, insertion ou mise à jour. Les curseurs sont généralement utilisés pour lire les géométries existantes et écrire de nouvelles géométries.

Chaque type de curseur est créé par une fonction ArcPy correspondante (SearchCursor, InsertCursor ou UpdateCursor) dans une table, une vue tabulaire, une classe d'entités ou une couche d'entités. Un curseur de recherche peut servir à extraire des lignes. Un curseur de mise à jour permet de mettre à jour et de supprimer des lignes, tandis qu'un curseur d'insertion permet d'insérer des lignes dans une table ou une classe d'entités.

Curseur

Explication

InsertCursor(jeu de données, {référence_spatiale})

Insère des lignes

SearchCursor(jeu de données, {clause_where}, {référence_spatiale}, {champs}, {champs_tri})

Accès en lecture seule

UpdateCursor(jeu de données, {clause_where}, {référence_spatiale}, {champs}, {champs_tri})

Met à jour ou supprime des lignes

Fonctions de curseur

RemarqueRemarque :

Les curseurs tiennent comptent des ensembles de définition de la couche/vue tabulaire et des sélections. L'objet curseur contient uniquement les lignes utilisées par tout outil de géotraitement lors d'une opération.

Chacune des trois fonctions de curseur crée un objet curseur permettant d'accéder aux objets ligne. Les méthodes prises en charge par l'objet ligne dépendent du type de curseur créé.

Les curseurs ne peuvent être parcourus que dans un sens (vers l'avant) ; ils ne permettent pas la sauvegarde ni l'extraction de lignes déjà extraites, ni les envois multiples de données. Si un script doit traiter des données à plusieurs reprises, l'application doit réexécuter la fonction de curseur. Si les deux exécutions sont effectuées au cours de la même session de mise à jour (ou une transaction de base de données avec le niveau d'isolement correspondant), l'application ne tient pas compte des modifications apportées aux données par d'autres applications en cours d'exécution.

Les curseurs de recherche ou de mise à jour peuvent être répétés par itération avec une boucle For ou dans une boucle While en utilisant la méthode next du curseur pour renvoyer la ligne suivante. Lors de l'utilisation de la méthode next sur un curseur pour extraire toutes les lignes d'une table contenant N lignes, le script doit créer N appels à next. L'appel de next après l'extraction de la dernière ligne du jeu de résultats renvoie la valeur None, représentant un type de données Python servant ici d'espace réservé.

Cet exemple affiche une opération de curseur simple. Il affiche le nom et la valeur de chaque champ de type chaîne pour chaque enregistrement d'une classe d'entités.

import arcpy

fc = "D:/st_johns/roads.shp"

# Create a search cursor 
#
rows = arcpy.SearchCursor(fc) 

# Create a list of string fields
fields = arcpy.ListFields(fc, "", "String")

for row in rows:
    for field in fields:
        if field.type != "Geometry":
            print "%s: Value = %s" % (field.name, row.getValue(field.name))

Tous les objets ligne extraits d'une table contiennent logiquement le même jeu ordonné de champs. En particulier, l'ordre des champs dans une ligne d'une table est identique à celui des champs renvoyés par la fonction ListFields. La ligne contient uniquement les champs visibles de la table utilisée pour créer le curseur, chaque nom de champ représentant une propriété de l'objet.

Objet curseur

Les fonctions SearchCursor, UpdateCursor et InsertCursor créent un objet curseur (également nommé objet d'énumération) permettant d'explorer les enregistrements par itération. Les méthodes de l'objet curseur créé à l'aide des différentes fonctions de curseur varient selon le type de curseur créé.

Le diagramme suivant montre les méthodes prises en charge pour chaque type de curseur :

Type de curseur

Méthode

Effet sur la position

Rechercher

next

Extrait le prochain objet ligne

Insérer

newRow

Crée un objet ligne vide

insertRow

Insère un objet ligne dans la table

next

Extrait le prochain objet ligne

Mettre à jour

updateRow

Met à jour la ligne courante avec un objet ligne modifié

deleteRow

Supprime la ligne de la table

next

Extrait le prochain objet ligne

insertRow

Le curseur d'insertion permet de créer de nouvelles lignes et de les insérer. Le flux de base du traitement consiste à utiliser la méthode newRow sur l'objet curseur dans lequel les lignes doivent être insérées. Ce nouvel objet ligne contient tous les champs figurant dans la table et vous pouvez affecter des valeurs aux champs de la ligne avant de l'insérer à l'aide de la méthode insertRow.

import arcpy

# Create insert cursor for table
#
rows = arcpy.InsertCursor("D:/St_Johns/data.gdb/roads_lut")
x = 1

# Create 25 new rows. Set the initial row ID and distance values
#
while x <= 25:
    row = rows.newRow()
    row.rowid = x
    row.distance = 100
    rows.insertRow(row)
    x = x + 1

updateRow

La méthode updateRow permet de mettre à jour la ligne au niveau de la position actuelle d'un curseur de mise à jour. Après l'extraction d'un objet ligne à partir de l'objet curseur, vous pouvez modifier la ligne selon vos besoins et appeler la méthode updateRow, transmettant ainsi la ligne modifiée.

import arcpy

# Create update cursor for feature class
#
rows = arcpy.UpdateCursor("D:/St_Johns/data.gdb/roads")

for row in rows:
# Update the field used in buffer so the distance is based on the road
#   type. Road type is either 1, 2, 3, or 4. Distance is in meters.
#
    row.buffer_distance = row.road_type * 100
    rows.updateRow(row)

deleteRow

La méthode deleteRow permet de supprimer la ligne au niveau de la position actuelle d'un curseur de mise à jour. Après avoir extrait l'objet ligne, appelez la méthode deleteRow sur le curseur pour supprimer la ligne.

import arcpy

# Create update cursor for feature class
#
rows = arcpy.UpdateCursor("D:/St_Johns/data.gdb/roads")

for row in rows:
    # Delete all rows that have a roads type of 4
    if row.road_type == 4:
        rows.deleteRow(row)

getValue et setValue

Il existe deux méthodes de base pour extraire et définir des valeurs de champ sur une ligne :

Méthode

Explication

getValue(nom_du_champ)

Extrait la valeur du champ

isNull(nom_du_champ)

Indique si la valeur du champ est nulle

setNull(nom_du_champ)

Définit une valeur nulle pour le champ

setValue (nom_du_champ, objet)

Définit la valeur du champ

Méthodes d'enregistrement

L'exemple ci-dessous crée une table de correspondance pour toutes les classes d'entités surfaciques d'un espace de travail. La table de correspondance contient un ID correspondant au champ IdObjet pour chaque entité de la classe d'entités et une valeur de distance utilisable par l'outil Zone tampon.

import arcpy
from arcpy import env
import os

env.overwriteOutput = 1
env.workspace = arcpy.GetParameterAsText(0)

# List the polygon feature classes
#
fcs = arcpy.ListFeatureClasses("*","polygon")

# Loop through the results.
#
for fc in fcs:
   # Get the ObjectID field
   #
   desc = arcpy.Describe(env.workspace + os.sep + fc)
   OIDFieldName = desc.OIDFieldName

   # Create lookup table name
   #
   if fc.endswith(".shp"):
      tab = fc.replace(".", "_lut.")
   else:
      tab = fc + "_lut"

   # Create lookup table and add fields
   #
   arcpy.CreateTable_management(env.workspace, tab)
   arcpy.AddField_management(tab,"id","long")
   arcpy.AddField_management(tab,"dist","long")

   # Open insert cursor on new lookup table
   #
   tabcur = arcpy.InsertCursor(env.workspace + os.sep + tab)

   # Open search cursor on feature class
   #
   featcur = arcpy.SearchCursor(env.workspace + os.sep + fc)

   # Loop through the rows in the feature class
   #
   for f_row in featcur:
       # Create a new row for the lookup table and set its ID to be the
       #  same as the feature OID and set the distance to 100.
       #
       t_row = tabcur.newRow()
       t_row.id = f_row.getValue(OIDFieldName)
       t_row.dist = 100

       # Insert the row into the lookup table and get the next row
       #  from the feature class
       #
       tabcur.insertRow(t_row)

Curseurs et verrouillage

Les curseurs d'insertion et de mise à jour tiennent compte des verrouillages de table définis par les applications ArcGIS. Les verrouillages empêchent plusieurs processus de modifier le même tableau au même moment. Il existe deux types de verrouillage : partagés et exclusifs.

Les curseurs de mise à jour et d'insertion ne peuvent pas être créés pour une table ou une classe d'entités si un verrouillage exclusif existe déjà pour ce jeu de données. Les fonctions UpdateCursor ou InsertCursor échouent en raison d'un verrouillage exclusif sur le jeu de données. Si ces fonctions créent un curseur, elles appliquent un verrouillage exclusif sur le jeu de données. Par conséquent, deux scripts ne peuvent pas créer un curseur de mise à jour ou d'insertion sur le même jeu de données.

Les verrouillages persistent jusqu'à ce que l'application ou le script libère le jeu de données, en fermant ou en libérant de façon explicite l'objet curseur. Dans un script, l'objet curseur doit être supprimé afin que le verrouillage exclusif qu'il a placé sur le jeu de données soit libéré. Sinon, toutes les autres applications ou scripts risquent de ne pas pouvoir accéder au jeu de données. L'exemple ci-dessous montre comment ouvrir et libérer un curseur de mise à jour. Un gestionnaire d'erreur permet de vérifier si la fonction UpdateCursor a échoué en raison de la présence d'un autre verrouillage exclusif dans la table.

import arcpy

# Create update cursor for feature class
#
try:
    # The variables row and rows are initially set to None, so that they
    #  can be deleted in the finally block regardless of where (or if)
    #  script fails.
    #
    row, rows = None, None

    rows = arcpy.UpdateCursor("D:/St_Johns/data.mdb/roads")

    # Update the field used in buffer so the distance is based on the 
    #   road type. Road type is either 1, 2, 3 or 4. Distance is in meters.
    #
    for row in rows:
        row.buffer_distance = row.road_type * 100
        rows.updateRow(row)

except:
    if not arcpy.GetMessages() == "":
        arcpy.AddMessage(arcpy.GetMessages(2))

finally:
    # Regardless of whether the script succeeds or not, delete 
    #  the row and cursor
    #
    if row:
        del row
    if rows:
        del rows

Une session de mise à jour dans ArcMap applique un verrouillage partagé aux données lors de la session de mise à jour. Un verrouillage exclusif est appliqué lorsque les mises à jour sont enregistrées. Un jeu de données ne peut pas être modifié si un verrouillage exclusif existe déjà.

Lorsque vous utilisez un éditeur Python tel que PythonWin, vous devez éventuellement nettoyer les références de l'objet afin de supprimer les verrouillages du jeu de données définis par les curseurs. Utilisez le module garbage collection (gc) pour décider quand supprimer des objets et/ou supprimer de façon explicite les références dans votre script.

Rubriques connexes


7/10/2012