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 |
---|---|
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 |
ArcGIS 10.1 apporte un nouveau module d'accès aux données (arcpy.da). Les curseurs précédents (qui sont toujours répertoriés dans arcpy) sont encore fonctionnels et valides. Toutefois, les performances des nouveaux curseurs arcpy.da sont considérablement plus rapides. Dans la plupart des cas, l'aide illustrera l'utilisation des curseurs arcpy.da. Pour plus d'informations sur le modèle "classique" de curseur, reportez-vous au tableau ci-dessous.
Curseur |
Explication |
---|---|
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 |
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.
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 traiter des données à plusieurs reprises, la méthode reset du curseur risque d’être appelée.
Les curseurs de recherche ou de mise à jour peuvent être itérés avec une boucle For. La prochaine ligne est également accessible en utilisant explicitement la méthode next du curseur pour renvoyer la prochaine ligne. 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. Une fois que la dernière ligne du jeu de résultats a été récupérée, un appel à next 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. L'avantage de l'utilisation d’une instruction With est qu'elle garantit la fermeture et l’ouverture des verrous des bases de données, ainsi que l’itération de réinitialisation, quelle que soit la circonstance (que le curseur soit terminé ou qu’une exception ait eu lieu).
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 la forme d’une liste de valeurs de champ. Les valeurs sont renvoyées dans le même ordre que celui fourni à l'argument field_names du curseur. La propriété fields d'un curseur peut également servir à confirmer l'ordre des valeurs de champ.
Objet curseur
SearchCursor, UpdateCursor et InsertCursor créent un objet curseur qui permet d’itérer les 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 curseur |
Méthode |
Effet sur la position |
---|---|---|
arcpy.da.SearchCursor |
next() |
Extrait la prochaine ligne |
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 |
|
next() |
Extrait la prochaine ligne |
|
reset() | Redéfinit la position de début du curseur |
insertRow
Un curseur d'insertion permet de créer de nouvelles lignes et de les insérer. Une fois que le curseur a été créé, la méthode insertRow permet d'insérer une liste (ou tuple) de valeurs qui composeront 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 x in range(0,25):
cursor.insertRow([x, 100])
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'une 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
#
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 rowtype 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 au niveau de la position actuelle d'un curseur de mise à jour. Après avoir extrait la ligne, appelez la méthode deleteRow sur le curseur pour supprimer la ligne.
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 par le curseur, elle est renvoyée sous forme de liste de valeurs de champ qui correspondent par position d'index.
Dans l'exemple ci-dessous, le nom d'état et la densité de population sont accessibles par 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('{0} has a population of {1}'.format(row[0], row[1]))
Bien que tous les champs soient accessibles à l'aide d'un astérisque (*), cette procédure n'est généralement pas recommandée. 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 nécessitent un champ de géométrie, généralement nommé Shape (mais pas toujours). Le jeton OID@ permet d'accéder au champ ObjectID et le jeton SHAPE@ (qui renvoie un objet géométrie) permet d'accéder au champ de géométrie d'une classe d'entités sans connaître préalablement les noms de champ.
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 {0}:".format(row[0]))
# For each point in the multipoint feature,
# print the x,y coordinates
for pnt in row[1]:
print("{0}, {1}".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'intégralité 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 représentant 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 le même tableau au même moment. Il existe deux types de verrouillage : partagés et exclusifs.
- Un verrouillage partagé est exécuté à 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à. L'affichage d'une classe d'entités dans ArcMap et l'aperçu d'une table dans ArcCatalog sont des exemples d'application d'un verrouillage partagé.
- Les verrouillages exclusifs sont appliqués lorsque des modifications sont apportées à une table ou une classe d'entités. La mise à jour et l'enregistrement d'une classe d'entités dans ArcMap, la modification de la structure d'une table dans ArcCatalog ou l'utilisation d'un curseur d'insertion sur une classe d'entités dans un IDE Python tel que PythonWin sont des exemples d'application d'un verrouillage exclusif par ArcGIS.
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.
Dans Python, le verrou demeure jusqu'à ce que le curseur soit relâché. Sinon, toutes les autres applications ou scripts risquent de ne pas pouvoir accéder au jeu de données. Un curseur peut être relâché par :
- l’inclusion du curseur dans une instruction With, ce qui garantit l’ouverture des verrous, que le curseur soit terminé ou non ;
- l’appel de la méthode reset() sur le curseur ;
- l’achèvement du curseur ;
- la suppression explicite du curseur à l'aide de l'instruction del de Python.
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à.
Curseur et champs BLOB
Un BLOB représentent 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 peuvent accepter des chaînes, bytearrayet memoryviews. Lors de la lecture de 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())