gpt4 book ai didi

python - 与新模型中多种类型(多态性)的关系

转载 作者:行者123 更新时间:2023-11-28 18:32:23 33 4
gpt4 key购买 nike

自 2014 年以来,存在与多个对象类型的关系不可用的问题: https://github.com/robinedwards/neomodel/issues/126

现在是 2016 年,我仍然不知道关于这个关键问题的任何解决方案。

用法示例:

class AnimalNode(StructuredNode):
tail_size = IntegerProperty()
age = IntegerProperty()
name = StringProperty()

class DogNode(AnimalNode):
smell_level = IntegerProperty()

class CatNode(AnimalNode):
vision_level = IntegerProperty()

class Owner(StructuredNode):
animals_owned = RelationshipTo("AnimalNode", "OWNED_ANIMAL")

dog_node1 = DogNode(name="Doggy", tail_size=3, age=2, smell_level=8).save()
cat_node1 = CatNode(name="Catty", tail_size=3, age=2, vision_level=8).save()

owner = Owner().save()
owner.animals_owned.connect(dog_node1)
owner.animals_owned.connect(cat_node1)

如果我尝试访问 owneranimals_owned 关系,如您所料,它只会检索 AnimalNode 基类而不是其子类(DogNodeCatNode),所以我无法访问属性:smell_levelvision_level

我希望在 neomodel 中允许这样的事情:

class Owner(StructuredNode):
animals_owned = RelationshipTo(["DogNode", "CatNode"], "OWNED_ANIMAL")

然后当我访问 owneranimals_owned 关系时,它将检索 DogNodeCatNode 类型的对象> 这样我就可以根据需要访问子类属性。

但是 connect 方法会产生以下错误:

TypeError: isinstance() arg 2 must be a type or tuple of types 

有什么方法可以优雅地在 neomodel 中实现这一点?

谢谢!

最佳答案

为了实现具有继承性的元数据模型,我最近做了类似的事情。相关代码在这里:https://github.com/diging/cidoc-crm-neo4j/blob/master/crm/models.py

基本上,我采用的方法是使用普通的多重继承来构建模型,neomodel 可以方便地将其转换为节点上相应的多个标签。这些模型都是基于 neomodel 的 StructuredNode 的抽象子类;我使用 labels()inherited_labels() 实例方法添加了在类层次结构的各个级别重新实例化节点的方法。例如,此方法会将节点重新实例化为其最派生类或其层次结构中的特定类:

class HeritableStructuredNode(neomodel.StructuredNode):
def downcast(self, target_class=None):
"""
Re-instantiate this node as an instance its most derived derived class.
"""
# TODO: there is probably a far more robust way to do this.
_get_class = lambda cname: getattr(sys.modules[__name__], cname)

# inherited_labels() only returns the labels for the current class and
# any super-classes, whereas labels() will return all labels on the
# node.
classes = list(set(self.labels()) - set(self.inherited_labels()))

if len(classes) == 0:
return self # The most derivative class is already instantiated.
cls = None

if target_class is None: # Caller has not specified the target.
if len(classes) == 1: # Only one option, so this must be it.
target_class = classes[0]
else: # Infer the most derivative class by looking for the one
# with the longest method resolution order.
class_objs = map(_get_class, classes)
_, cls = sorted(zip(map(lambda cls: len(cls.mro()),
class_objs),
class_objs),
key=lambda (size, cls): size)[-1]
else: # Caller has specified a target class.
if not isinstance(target_class, basestring):
# In the spirit of neomodel, we might as well support both
# class (type) objects and class names as targets.
target_class = target_class.__name__

if target_class not in classes:
raise ValueError('%s is not a sub-class of %s'\
% (target_class, self.__class__.__name__))
if cls is None:
cls = getattr(sys.modules[__name__], target_class)
instance = cls.inflate(self.id)

# TODO: Can we re-instatiate without hitting the database again?
instance.refresh()
return instance

请注意,这之所以有效,部分原因是所有模型都在同一个命名空间中定义;如果不是这样,这可能会变得棘手。这里还有一些问题需要解决,但它可以完成工作。

使用这种方法,您可以定义与上级类的关系,然后连接节点与下级/更多派生类实例化。然后在检索时,将它们“向下转换”到它们的原始类(或层次结构中的某个类)。例如:

>>> for target in event.P11_had_participant.all():
... original_target = target.downcast()
... print original_target, type(original_target)
{'id': 39, 'value': u'Joe Bloggs'} <class 'neomodel.core.E21Person'>

参见 this README用于使用示例。

关于python - 与新模型中多种类型(多态性)的关系,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35744456/

33 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com