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 possèdent trois formes : recherche, insertion et 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éé au moyen d’une fonction ArcPy correspondante (SearchCursor, InsertCursor ou UpdateCursor) sur 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.

CurseurExplication

arcpy.da.InsertCursor(in_table, field_names)

Insère des lignes

arcpy.da.SearchCursor(in_table, field_names, {where_clause}, {spatial_reference}, {explode_to_points}, {sql_clause})

Accès en lecture seule

arcpy.da.UpdateCursor(in_table, field_names, {where_clause}, {spatial_reference}, {explode_to_points}, {sql_clause})

Met à jour ou supprime des lignes

Fonctions des curseurs d’accès aux données (arcpy.da)
Héritage :

Un nouveau module d’accès aux données (arcpy.da) a été ajouté dans ArcGIS 10.1. Les curseurs existants (toujours répertoriés sous arcpy) restent fonctionnels et valides ; toutefois, les nouveaux curseurs arcpy.da offrent des performances nettement plus rapides. Dans la plupart des cas, la documentation d’aide décrit l’utilisation des curseurs arcpy.da. Pour plus d'informations sur le modèle classique de curseur, reportez-vous au tableau ci-dessous.

CurseurExplication

arcpy.InsertCursor(dataset, {spatial_reference})

Insère des lignes

arcpy.SearchCursor(dataset, {where_clause}, {spatial_reference}, {fields}, {sort_fields})

Accès en lecture seule

arcpy.UpdateCursor(dataset, {where_clause}, {spatial_reference}, {fields}, {sort_fields})

Met à jour ou supprime des lignes

Fonctions des curseurs (arcpy)
Remarque :

Les curseurs respectent les ensembles de définition et les sélections des couches et vues tabulaires. L'objet curseur contient uniquement les lignes utilisées par tout outil de géotraitement lors d'une opération.

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. Si un script doit parcourir plusieurs fois les données, la méthode reset du curseur peut être appelée.

L’itération des curseurs de recherche ou de mise à jour est possible avec une boucle for. La ligne suivante est également accessible en utilisant explicitement la méthode next 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 appeler next N fois. Un appel de next après que la dernière ligne du jeu de résultats a été extraite renvoie une exception StopIteration.

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

Les curseurs de recherche et de mise à jour prennent également en charge les instructions with.

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

Chaque ligne extraite d’une table est renvoyée sous forme de liste de valeurs de champ. Les valeurs sont renvoyées dans l’ordre dans lequel elles ont été transmises à l’argument field_names du curseur. La propriété fields d’un curseur peut également être utilisée pour vérifier l’ordre des valeurs de champ.

Les objets curseurs

SearchCursor, UpdateCursor et InsertCursor créent un objet curseur qui peut être utilisé pour l’itération des enregistrements. 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 par chaque type de curseur :

Type de curseurMéthodeEffet sur la position

arcpy.da.SearchCursor

reset()

Redéfinit la position de début du curseur

arcpy.da.InsertCursor

insertRow()

Insère une ligne dans la table

arcpy.da.UpdateCursor

updateRow()

Met à jour la ligne courante

deleteRow()

Supprime la ligne de la table

reset()

Redéfinit la position de début du curseur

insertRow

Un curseur d’insertion permet de créer des lignes et de les insérer. Une fois le curseur créé, la méthode insertRow est utilisée pour insérer une liste (ou tuple) de valeurs qui constitueront la nouvelle ligne. Les champs du tableau qui ne sont pas inclus dans le curseur se verront attribuer la valeur par défaut du champ.

import arcpy
# Create insert cursor for table
cursor = arcpy.da.InsertCursor("c:/base/data.gdb/roads_lut", 
                               ["roadID", "distance"])
# Create 25 new rows. Set the initial row ID and distance values
for i in range(0,25):
    cursor.insertRow([i, 100])

updateRow

La méthode updateRow permet de mettre à jour la ligne à la position actuelle d’un curseur de mise à jour. Après le renvoi d’une ligne à partir de l’objet curseur, vous pouvez modifier cette ligne selon vos besoins et appeler updateRow en transmettant la ligne modifiée.

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

La méthode deleteRow permet de supprimer la ligne à la position actuelle d’un curseur de mise à jour. Après l’extraction de la ligne, appelez deleteRow sur le curseur pour la supprimer.

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()

Accès et définition des valeurs de champ

Pour chaque curseur, les champs utilisés sont fournis par une liste (ou tuple) de noms de champ. Lorsqu’une ligne est renvoyée à partir du curseur, elle l’est sous la forme d’une liste de valeurs de champ correspondant à une position d’index.

Dans l’exemple ci-dessous, l’accès au nom de l’état et à la population se fait selon leur position.

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]))
Astuce :

Bien qu’il soit possible d’accéder à tous les champs en utilisant un astérisque (*), cela est généralement déconseillé. Plus le nombre de champs spécifiés est élevé et plus le curseur s’exécute lentement. Répertoriez uniquement les champs que vous pensez utiliser afin d’améliorer les performances globales du curseur.

Les jetons peuvent également être utilisés en tant que raccourcis au lieu des noms de champ. Toutes les tables incluent un champ ObjectID qui peut avoir beaucoup de noms différents selon le type de données. Les classes d’entités simples requièrent un champ de géométrie, généralement (mais pas toujours) nommé Shape. Le jeton OID@ peut être utilisé pour accéder au champ ObjectID et le jeton SHAPE@ (qui renvoie un objet de géométrie), pour accéder au champ de géométrie d’une classe d’entités sans connaître les noms des champs.

Curseur de recherche dans une classe d'entités multi-points
import arcpy
infc = arcpy.GetParameterAsText(0)
# Enter for loop for each feature
for row in arcpy.da.SearchCursor(infc, ["OID@", "SHAPE@"]):
    # Print the current multipoint's ID
    print("Feature {}:".format(row[0]))
    # For each point in the multipoint feature,
    #  print the x,y coordinates
    for pnt in row[1]:
        print("{}, {}".format(pnt.X, pnt.Y))

Les jetons de géométrie supplémentaires peuvent permettre d’accéder à des informations de géométrie spécifiques. L’accès à l’ensemble de la géométrie prend plus de temps. Si vous n’avez besoin que de propriétés spécifiques de la géométrie, utilisez les jetons pour fournir des raccourcis permettant d’accéder aux propriétés de géométrie. Par exemple, SHAPE@XY renvoie un tuple de coordonnées x,y qui représentent le centroïde de l’entité.

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 la même table au même moment. Il existe deux types de verrouillage, partagé et exclusif, qui sont décrits ci-dessous :

  • Un verrouillage partagé est appliqué à chaque ouverture d’une table ou d’un jeu de données. Plusieurs verrouillages partagés peuvent coexister pour une table, mais aucun verrouillage exclusif n’est autorisé si un verrouillage partagé existe déjà. Par exemple, un verrouillage partagé est appliqué lors de l’affichage d’une classe d’entités et de l’aperçu d’une table.
  • Les verrouillages exclusifs sont appliqués lorsque des modifications sont apportées à une table ou une classe d’entités. Par exemple, un verrouillage exclusif est appliqué par ArcGIS lors de la mise à jour et de l’enregistrement d’une classe d’entités dans une carte, de la modification de la structure d’une table ou de l’utilisation d’un curseur d’insertion sur une classe d’entités dans un IDE Python.

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. La fonction UpdateCursor ou InsertCursor échoue car un verrouillage exclusif est appliqué au 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.

Dans Python, le verrou demeure jusqu’à ce que le curseur soit relâché. Sinon, les autres applications ou scripts risquent de ne pas pouvoir accéder au jeu de données. Un curseur peut être relâché par :

  • Inclure le curseur dans une instruction with, ce qui garantit la relâche des verrouillages, que le curseur ait été exécuté avec succès ou non.
  • Appeler reset sur le curseur.
  • Le curseur est exécuté avec succès.
  • Supprimer explicitement le curseur à l’aide de l’instruction Python del.

Une session de mise à jour applique un verrouillage partagé aux données pendant 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à.

Curseur et champs BLOB

Un grand objet binaire (Binary Large Object, BLOB) représente des données stockées sous forme d’une longue séquence de nombres binaires. ArcGIS stocke les annotations et les dimensions en tant qu'objets BLOB et les éléments tels que des images, des éléments multimédias ou des parties de codes peuvent être stockés dans ce type de champ. Vous pouvez utiliser un curseur pour charger ou afficher le contenu d'un champ BLOB.

Dans Python, les champs BLOB acceptent les chaînes, bytearray et memoryviews. Lors de la lecture des champs BLOB, un objet memoryview est renvoyé.

import arcpy
data = open("c:/images/image1.png", "rb").read()
ic = arcpy.da.InsertCursor("c:/data/fgdb.gdb/fc", ['imageblob'])
ic.insertRow([data])
import arcpy sc = arcpy.da.SearchCursor("c:/data/fgdb.gdb/fc", ["imageblob"]) memview = sc.next()[0] open("c:/images/image1_copy.png", "wb").write(memview.tobytes())