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 |
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 :
- à l'aide du nom de champ, comme dans value = row.road_type,
- à l'aide de getValue et setValue, comme dans value = row.getValue("road_type").
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 |
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.
- 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.
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.