如何用Owlready2实现类与个体分属不同IRI的定义?
问题:Owlready2中通过完整IRI直接创建跨命名空间个体
我们在Owlready2中需要将类定义在指定本体基IRI(http://example.com/ontology/item/1.1#)下,但创建的个体要归属另一个独立IRI(如http://example.com/profile/item/resource/)。现有实例化方式必须分别传入name和namespace两个参数,使用起来比较繁琐,希望能直接传入完整IRI就创建个体,比如写成stuff = Stuff('http://example.com/profile/item/resource/8gdfb186-fc78-4b9e-95c4-545339d3ce1b')。之前尝试重载__new__方法实现时,出现了IRI重复拼接的错误,现在需要可行的解决办法。
原有实现代码
from owlready2 import * from rdflib import URIRef onto = get_ontology('http://example.com/ontology/item/1.1#') class Stuff(Thing): namespace = onto # 当前需要分开传参的实例化方式 stuff = Stuff( name='8gdfb186-fc78-4b9e-95c4-545339d3ce1b', namespace='http://example.com/profile/item/resource/' )
尝试的重载__new__代码(存在IRI重复拼接问题)
from owlready2 import * from rdflib import URIRef class Stuff(Thing): namespace = onto def __new__(Class, name=None, namespace=None, is_a=None, **kwargs): if name and isinstance(name, URIRef): splitted = str(name).rsplit('/', 1) if len(splitted) == 2: new_namespace = onto.get_namespace(f'{splitted[0]}/') obj = Thing.__new__( Class, name=splitted[1], namespace=new_namespace, is_a=is_a, **kwargs ) obj.namespace = new_namespace obj.namespace.ontology._base_iri = f'{splitted[0]}/' obj.set_name(f'{splitted[1]}') return obj obj = Thing.__new__( Class, name=name, namespace=namespace, is_a=is_a, **kwargs ) return obj
可行解决方案
之前的错误在于修改了本体的_base_iri,干扰了Owlready2原本的IRI构建逻辑,导致重复拼接。其实Owlready2本身支持直接通过iri参数创建个体,我们只需要简化重载逻辑即可。
方案一:兼容两种传参方式
from owlready2 import * from rdflib import URIRef onto = get_ontology('http://example.com/ontology/item/1.1#') class Stuff(Thing): namespace = onto def __new__(cls, iri_or_name, **kwargs): # 处理完整IRI传入的情况 if isinstance(iri_or_name, (URIRef, str)): return super().__new__(cls, iri=URIRef(iri_or_name), **kwargs) # 兼容原有传入name的方式 return super().__new__(cls, name=iri_or_name, **kwargs) # 直接用完整IRI创建个体 stuff = Stuff('http://example.com/profile/item/resource/8gdfb186-fc78-4b9e-95c4-545339d3ce1b') # 验证结果 print(stuff.iri) # 输出:http://example.com/profile/item/resource/8gdfb186-fc78-4b9e-95c4-545339d3ce1b
方案二:更灵活的参数处理(支持可选namespace)
如果需要保留传入namespace的兼容性,可以稍微调整:
from owlready2 import * from rdflib import URIRef onto = get_ontology('http://example.com/ontology/item/1.1#') class Stuff(Thing): namespace = onto def __new__(cls, iri_or_name=None, namespace=None, **kwargs): # 当传入完整IRI且未指定namespace时,直接用iri创建 if iri_or_name and isinstance(iri_or_name, (URIRef, str)) and not namespace: return super().__new__(cls, iri=URIRef(iri_or_name), **kwargs) # 原有传参逻辑 return super().__new__(cls, name=iri_or_name, namespace=namespace, **kwargs) # 两种方式都能正常工作 stuff1 = Stuff('http://example.com/profile/item/resource/8gdfb186-fc78-4b9e-95c4-545339d3ce1b') stuff2 = Stuff(name='test-id', namespace='http://example.com/profile/item/resource/')
核心说明
Owlready2的Thing.__new__方法本身就支持iri参数,直接传入完整IRI就能绕过namespace + name的拼接逻辑,不需要手动拆分修改命名空间,这才是最简洁可靠的实现方式。
内容的提问来源于stack exchange,提问作者Bloodbee
相关产品推荐
相关产品推荐

