python - 类重复输入对象

标签 python scope immutability

我有两个 python 类对象,用于将数据从 Oracle 提取到 ArcMap。该过程中的各种事件使我从“列”对象列表开始并构建一个 pyTable 对象。 pyTable 对象有一个按名称插入字段的列表。在 __init__ 期间,我使用 getSelect() 函数填充插入字段列表。

我添加了一堆语句,以确保每次调用 pyTable 时都会得到一个新创建的对象,但我仍然看到一个奇怪的结果。我第一次使用该类,一切都很好。第二次发出相同的语句时,colList 是新的,但字段列表是重复的。我很抱歉没有清除无关的代码部分。

我在哪里弄乱了我的对象引用?

这里是执行结果。 myList 有 8 个列对象。

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

这是两个类:

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('SHAPE@WKT')
            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

最佳答案

您正在制作传递给 init 函数中的类的列表的浅拷贝。

参见Shallow and deep copy operations在 Python 文档中了解一些基本信息。

self.colList = ColList[:] 创建一个新的 LIST,但在该新列表中包含对原始列表(浅拷贝)中相同对象的引用。

您需要一个深拷贝:

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

深层复制有一个新列表,以及初始化为与原始列表中的对象匹配的新对象。因此,如果一个类列表中的对象发生变化,它们不会在每个类中发生变化。

关于python - 类重复输入对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44424459/

相关文章:

javascript - 如何将额外参数传递给 Javascript .filter() 方法中的回调函数?

javascript - 就在我认为我终于理解了 Javascript 作用域的时候

emacs - 本地到 `let` 与本地到函数

python - 如何使用 pyzmq 发送带有 PUB/SUB 模式的字典?

python - 无限抛硬币,当正面数量=反面数量时停止

python - 我如何删除条件列值上的全天行..pandas

java - 如何在 Spring Boot 2.2.4 中将 @ConstructorBinding 和 @PropertySource 与 @ConfigurationProperties 一起使用?

java - 具有 ArrayList 成员变量的不可变对象(immutable对象) - 为什么可以更改此变量?

python - 可变和不可变对象(immutable对象)

python - 导入错误: cannot import name Serializer