2017-06-07 3 views
1

Ich habe zwei Python-Klassenobjekte, mit denen ich Daten von Oracle nach ArcMap extrahiere. Die verschiedenen Aktivitäten in diesem Prozess veranlassen mich, mit einer Liste von "Spalten" -Objekten zu beginnen und ein Objekt pyTable zu erstellen. Das Objekt pyTable enthält eine Liste von Feldern mit Namen. Während __init__ verwende ich die getSelect() Funktion, um die Liste der einzufügenden Felder aufzufüllen.Klasse dupliziert Eingabeobjekte

Ich habe eine Reihe von Anweisungen hinzugefügt, um sicherzustellen, dass jedes Mal, wenn ich pyTable aufrufen ich ein neu erstelltes Objekt, aber ich sehe immer noch ein seltsames Ergebnis. Das erste Mal, wenn ich die Klasse benutze, ist alles in Ordnung. Das zweite Mal, wenn ich die gleiche Aussage mache, ist die colList neu, aber die Feldliste ist dupliziert. Ich entschuldige mich dafür, dass ich die überflüssigen Code-Abschnitte nicht bereinigt habe.

Wo vermassle ich meine Objektreferenzen?

Hier sind die Ergebnisse der Ausführung. myList hat 8 Spaltenobjekte.

>>> arcTable = pyTable(myList) 
>>> len(arcTable.getTuple()) 
8 
>>> arcTable = pyTable(myList) 
>>> len(arcTable.getTuple()) 
16 
>>> arcTable = pyTable(myList) 
>>> len(arcTable.getTuple()) 
8 
>>> arcTable = pyTable(myList) 
>>> len(arcTable.getTuple()) 
8 
>>> newTable = pyTable(myList) 
>>> len(newTable.getTuple()) 
8 
>>> thirdTable = pyTable(myList) 
>>> len(thirdTable.getTuple()) 
16 
>>> thirdTable = pyTable(myList) 
>>> len(thirdTable.getTuple()) 
24 
>>> thirdTable = pyTable(myList) 
>>> len(thirdTable.getTuple()) 
8 
>>> 

Hier sind die beiden Klassen:

import arcpy, cx_Oracle 

class column: 
    # Add to the arcType and cxType functions to support more Oracle data types. 
    # BLOB and CLOB fields will need additional support in Read and Write fx's. 
     name = '' 
     dataType = '' 
     dataLen = 1 
     dataPrecision = 0 
     dataScale = 0 
     query = '' 
     isShape = False 
     isLOB = False 

     def __init__(self, Name, DataType, DataLen, DataPrecision, DataScale): 
      self.name = Name 
      self.dataType = DataType 
      self.dataLen = DataLen 
      self.dataPrecision = DataPrecision 
      self.dataScale = DataScale 
      if DataType == 'WKT': 
       self.query = 'sdo_util.to_wktgeometry(t.' + Name + ') wkb, ' 
      else: 
       self.query = 't.' + Name 
      if DataType == 'SDO_GEOMETRY': 
       self.isShape = True 
      if DataType == 'BLOB' or DataType == 'CLOB' or DataType == 'WKT': 
       self.isLOB = True 

     def getArcType(self, *args):  # Data type translation 'Oracle_type':'ESRI_type' 
      return { 
#    'BINARY_DOUBLE':'DOUBLE', 
#    'BINARY_FLOAT':'FLOAT', 
#    'BLOB':'BLOB', 
       'CHAR':'STRING', 
       'CLOB':'CLOB', 
       'DATE':'DATE', 
#    'FLOAT':'FLOAT', 
#    'LONG':'LONG', 
#    'LONG RAW':'BLOB', 
       'NUMBER':'DOUBLE', 
#    'RAW':'BLOB', 
#    'ROWID':'SHORT', 
       'SDO_GEOMETRY':'GEOMETRY', 
       'VARCHAR2':'STRING', 
       'WKT':'WKT', 
      }.get(self.dataType,"undefined") 

     def getCxType(self, *args):  # Data type translation 'Oracle_type':'cx_Oracle.type' 
      return { 
       'BLOB':cx_Oracle.BLOB, 
       'CHAR':cx_Oracle.STRING, 
       'CLOB':cx_Oracle.CLOB, 
       'DATE':cx_Oracle.DATETIME, 
       'NUMBER':cx_Oracle.NUMBER, 
       'SDO_GEOMETRY':cx_Oracle.CLOB, 
       'VARCHAR2':cx_Oracle.STRING, 
      }.get(self.dataType,"undefined") 

class pyTable: 
    # Create an object to track columns for read and write operations. 
    # BLOB, CLOB and SDO_GEOMETRY types will need additional support in Read and Write fx's. 
    length = 0 
    # colList = []  # The original list of columns is coming from an Oracle query. 
    # These two lists are different because of the way I treat shape. 
    # I create a FC and then add attribute columns. This puts the Shape column first in the list. 
    __insCols = []  # I use insCols as a list of column type objects to write to ArcMap. 
    __insertFields = [] 
    __colTuple = None 
    __myData = [] 
    __pKey = 'P_KEY'  # The name of the primary key field should be <table>_CN 
    __insBlobCols = [] # A list of column positions that contain BLOB data types. 
    __insKeyCol = -1  # The position of the primary key column. 

    def __init__(self, ColList): 
     self.colList = ColList[:] 
     self.length = len(ColList) 
     self.isFC = self.__getShape() 
     self.__select = self.getSelect() 
     arcpy.AddMessage('New table class created with ' + str(self.length) + ' columns.') 

    def __del__(self): 
     self.colList = [] 
     del self.__insCols [:] 
     del self.__insertFields [:] 
     del self.__myData [:] 
     del self.__insBlobCols [:] 

    def addDataRow(self, inDataRow): 
     self.__myData.append(inDataRow) 

    def getInsCols(self): 
     return self.__insCols 

    def getTuple(self): 
     return self.__colTuple 

    def getPK(self): 
     return self.__pKey 

    def getInsBlobCols(self): 
     return self.__insBlobCols 

    def clearData(self): 
     self.__myData = [] 

    def getData(self): 
     return self.__myData 

    def getKeyCol(self): 
     return self.__insKeyCol 

    def __getShape(self): 
     isFeature = False 
     featureName = '' 
     for col in self.colList: 
      if col.isShape: 
       isFeature = True 
       featureName = col.name 
     if isFeature: 
      wktShape = column(featureName, 'WKT', 0, 0, 0) 
      self.__insCols.append(wktShape) 
     for col in self.colList: 
      if not col.isShape: 
       self.__insCols.append(col) 
     return isFeature 

    def getSelect(self): 
     # Build the select statement 
     # Build the list of insert Field names 
     # Build the Tuple of insert Field names 
     # Identify the LOB columns by index number 
     statement = 'select ' 
     del self.__insertFields[:] 
     indx = 0 
#  print ('Table has ', len(self.__insCols), ' insert columns.') 
     for col in self.__insCols: 
      if col.dataType == 'WKT': 
       statement += 'sdo_util.to_wktgeometry(t.shape) wkb, ' 
       self.__insertFields.append('[email protected]') 
      else: 
       statement += 't.' + col.name + ', ' 
       self.__insertFields.append(col.name) 
       if col.dataType == 'BLOB': 
        self.__insBlobCols.append(indx) 
      # 
      # ToDo: The key column should be <table>_CN 
      # But, the logic needs to work for views with different names. 
      # 
      if col.name == self.__pKey: 
       self.__insKeyCol = indx 
      indx += 1 
     statement = statement[:statement.rfind(',')] # Trim off the trailing comma 
#  print ('Insert is composed of ', len(self.__insertFields), ' fields.') 
     self.__colTuple = tuple(self.__insertFields) 
     return statement 

    def createTemp(self, WorkSpace, tempFC): 
     success = False 
     insertCols = self.__insCols 
     arcpy.AddMessage('Adding ' + tempFC + ' with ' + str(len(insertCols)) + ' columns.') 
     try: 
      if self.isFC: 
       arcpy.CreateFeatureclass_management(WorkSpace, tempFC, 'POINT') 
       arcpy.AddMessage(tempFC + ' feature class was successfully created.') 
      else: 
       arcpy.CreateTable_management(WorkSpace, tempFC) 
       arcpy.AddMessage(tempFC + ' table was successfully created.') 
      for col in insertCols: 
       esriType = col.getArcType() 
       if esriType == "undefined": 
        arcpy.AddError('Data type not currently supported, ' + col.dataType) 
        return success 
       if col.dataType <> 'WKT': 
        arcpy.AddField_management(tempFC, col.name, esriType, col.dataPrecision, col.dataScale, col.dataLen) 
        arcpy.AddMessage('Created column: ' + col.name) 
      success = True 
     except: 
      e = sys.exc_info()[1] 
      arcpy.AddError('Create of ' + tempFC + ' failed with ' + str(e.args[0]))    
     return success 

Antwort

1

Sie sind eine flache Kopie der Liste Ihrer Klasse in der init-Funktion übergeben zu machen.

Weitere grundlegende Informationen finden Sie in der Python-Dokumentation unter Shallow and deep copy operations.

self.colList = ColList[:] erstellt eine neue LIST, aber innerhalb dieser neuen Liste sind Verweise auf die gleichen Objekte, die in der ursprünglichen Liste (eine flache Kopie) waren.

Sie benötigen eine tiefe Kopie:

import copy 
... 
self.colList = copy.deepcopy(ColList) 

Eine tiefe Kopie hat eine neue Liste, sowie neue Objekte initialisiert die Objekte in der ursprünglichen Liste übereinstimmen. Wenn sich also die Objekte in einer Klassenliste ändern, ändern sie sich nicht in jeder Klasse.

+0

Dank Robert. Ich musste die Kopierbibliothek in meine Python 2.7-Umgebung importieren. Ihr Vorschlag war der Schlüssel. – user2948567