Python 通过切换对象的类来管理对象
我有一个特定程序的数据输入文件。文件中有不同类型的数据行,对于每种类型的输入行,在我之前创建的另一个模块中都有一个对应的类。最简单的例子:Python 通过切换对象的类来管理对象,python,Python,我有一个特定程序的数据输入文件。文件中有不同类型的数据行,对于每种类型的输入行,在我之前创建的另一个模块中都有一个对应的类。最简单的例子: #data module class AnalysisObject: pass class BoundaryNode(AnalysisObject): pass class MaterialDefiniton(AnalysisObject): pass 根据它所表示的数据类型,为每一行分配一个类,并将该对象对应的AnalysisObject作为r/w属性描
#data module
class AnalysisObject: pass
class BoundaryNode(AnalysisObject): pass
class MaterialDefiniton(AnalysisObject): pass
根据它所表示的数据类型,为每一行分配一个类,并将该对象对应的AnalysisObject
作为r/w属性描述符,似乎是一个好主意,因此我首先建立了一个接口(由于下面解释的原因,我不能使用abc.ABCMetaclass
):
我的问题是如何将文件行的每一行分配给正确的类,同时保持数据输入模块和数据模块之间的分离
我的想法是首先将每一行加载到str
的子类中。然后,当调用该子类的任何方法时,该子类可以将该对象重新分配给正确的类(使用myobject.\uu class\uu=NewClass
)
这一切似乎都正常工作,但是,我不确定以这种方式重新分配对象的类是否是一个好主意。它似乎还没有给我带来任何问题,但我不是特别有经验,也不知道该找什么
class DataLine(LineBase):
def _switch_class(self,klass):
self.__class__ = klass
def __getattr__(self,name):
self.__class__ = line_type_detector(self.line)
return getattr(self, name)
附加说明:该类是我无法使LineBase成为abc.ABCMetaclassabc.ABCMetaclass
的原因:
@abc.abstract
def analysis_object(self): etc. etc. etc.
…因为这样在调用DataLine().analysis\u object
时就不会发生类重新分配
检测每一行应该是哪一类不是问题;我有一个简单的线型检测器
:
def line_type_detector(data_line):
-figure out what class the line should be-
return ItShouldBeThisClass
我不知道一旦构建了对象,如何更改它的类。所以我宁愿在创建时分配类。您可以使用函数
createLine
明确地执行此操作,该函数将返回相应子类的对象:
def createLine(data_line):
typ = line_type_detector
if (typ == BoundaryNodeLine):
return BoundaryNodeLine(data_line)
...
您也可以在LineBase
中使用\uuuuu new\uuuuu
特殊方法:
class LineBase:
def __new__(cls, data_line):
return createLine(data_line)
...
其中createLine与上述函数相同
然后,您只需使用以下工具创建对象:
line = LineBase(data_line)
并直接获得正确子类的对象我不知道在构建对象后如何更改对象的类。所以我宁愿在创建时分配类。您可以使用函数
createLine
明确地执行此操作,该函数将返回相应子类的对象:
def createLine(data_line):
typ = line_type_detector
if (typ == BoundaryNodeLine):
return BoundaryNodeLine(data_line)
...
您也可以在LineBase
中使用\uuuuu new\uuuuu
特殊方法:
class LineBase:
def __new__(cls, data_line):
return createLine(data_line)
...
其中createLine与上述函数相同
然后,您只需使用以下工具创建对象:
line = LineBase(data_line)
并直接获得正确子类的对象我不知道在构建对象后如何更改对象的类。所以我宁愿在创建时分配类。您可以使用函数
createLine
明确地执行此操作,该函数将返回相应子类的对象:
def createLine(data_line):
typ = line_type_detector
if (typ == BoundaryNodeLine):
return BoundaryNodeLine(data_line)
...
您也可以在LineBase
中使用\uuuuu new\uuuuu
特殊方法:
class LineBase:
def __new__(cls, data_line):
return createLine(data_line)
...
其中createLine与上述函数相同
然后,您只需使用以下工具创建对象:
line = LineBase(data_line)
并直接获得正确子类的对象我不知道在构建对象后如何更改对象的类。所以我宁愿在创建时分配类。您可以使用函数
createLine
明确地执行此操作,该函数将返回相应子类的对象:
def createLine(data_line):
typ = line_type_detector
if (typ == BoundaryNodeLine):
return BoundaryNodeLine(data_line)
...
您也可以在LineBase
中使用\uuuuu new\uuuuu
特殊方法:
class LineBase:
def __new__(cls, data_line):
return createLine(data_line)
...
其中createLine与上述函数相同
然后,您只需使用以下工具创建对象:
line = LineBase(data_line)
并直接获取正确子类的对象通常,当使用不同的类型来标识这种不同的数据时,更专门的类型将被期望具有额外的属性或方法,这些属性或方法对于它们来说是特殊的。例如,
materialdefinition
可能包含基本AnalysisObject
不包含的有关物料的信息。因此,选择不同类型的原因是能够存储不常见的属性
现在,如果情况并非如此,并且类型仅用于标识,而不用于状态或行为差异,那么您根本不应该使用不同的类型。只需使用一种类型,并使其具有类似kind
的属性,该属性告诉您所引用的数据类型。例如,您可以使用obj.kind='materialdefinition'
,或者obj.kind='boundarynode'
但我将假设情况并非如此,这些对象实际上是不同的,并且在解析一行时,您希望根据行类型使用值填充不同的属性
那么,数据类型能够自己解析这样的行有什么错呢?没什么,我想说。具有能够序列化或取消序列化的类型是非常常见的。我不认为这会是一个缺少关注点分离的问题;毕竟,类型确保其状态可以存储在文件中,或从文件加载
在Python中,您实际上可以实现一个类型的\uuuu repr\uuuu
方法来获取可以保存到文件中的字符串表示形式repr
旨在为您提供完全代表对象状态的内容。对于解析,您只需创建一个函数,该函数接受字符串并根据函数解析的内容返回其中一个对象。例如:
def parse (line):
data = line.split()
if data[0] == 'material':
obj = MaterialDefiniton()
obj.material = data[1]
obj.otherstuff = data[2]
elif data[0] == 'boundary':
obj = BoundaryNode()
obj.boundary = data[1]
else:
obj = AnalysisObject()
obj.raw_data = data
return obj
您还可以将对该类型的单独解析移动到该类型的构造函数中,这样您就可以将该行传递给对象,它们将自己构建。或者创建一个明确解析数据的classmethod:
class MaterialDefinition:
@classmethod
def parse (cls, data):
obj = cls() # This is equivalent to `obj = MaterialDefinition()`
obj.material = data[1]
obj.otherstuff = data[2]
return obj
然后,您可以在generalparse
函数中选择所需的对象:
def parse (line):
data = line.split()
if data[0] == 'material':
return MaterialDefinition.parse(data)
elif data[0] == 'boundary':
return BoundaryNode.parse(data)
else:
return AnalysisObject.parse(data)
您甚至可以移动解析函数的逻辑