【发布时间】:2016-12-09 21:39:18
【问题描述】:
我有一个 Python 包装的 api,我正在使用 swig 为其生成一个接口,我需要找到一种方法来使用 Python 内置函数 __getitem__ 用于类的不同组件。
一个简单的例子是:
obj = module.class()
for i in range(obj.numPart1()):
print (obj.part1[i])
for i in range(obj.numPart2()):
print (obj.part2[i])
如果这是完全错误的,并且有更“Pythonic”的方式来做到这一点,我会全力以赴。基础对象必须有两个部分,因为它是一个三角剖分,可以访问所有与同一个 C++ 后端相关联的顶点和面。
我环顾了很多地方,并尝试在 Python 中使用 metaclasses 和 super 函数,但运气不佳,主要是因为 SWIG 导致我的类布局方式。我也可能没有完全理解它们......
如果需要,我什至可以将项目添加到 C++ 端,如果我需要能够提供所需的东西,但我想最终得到一个可以访问对象具有的两个属性之一的类本质上是列表。添加到 C++ 端不太理想,因为代码在其他地方重复使用,所以我想尽可能减少对 C++ 代码的干扰。
使用 SWIG 会引起一些我应该提到的问题
-
__init__无法修改,因为它是在 SWIG 中生成的。我只能添加到课程中 - 我输入的任何 Python 代码都必须位于现有类中或位于文件顶部。 (我无法在文件中的任何位置添加类)。
下面是我希望通过具有一定代表性的代码示例访问的样子:
注意:本示例中的所有函数都是包装的 C++ 函数,除了包装的内置函数 (__getitem__,__enter__,__exit__)
import ModTest as m
with m.multiAttrObj() as obj:
print ("Attribute A:")
for i in range(obj.nAttrA()):
#print (obj.getAttrA(i)) # This version works
print (obj.AttrA[i]) # This version fails
print ("\nAttribute B:")
for i in range(obj.nAttrB()):
#print (obj.getAttrB(i)) # This version works
print (obj.AttrB[i]) # This version fails
我的模块大概是这样的:
#ModTest.py
class multiAttrObj():
# Init method cannot be changed...generated by SWIG (in real case)
def __init__(self):
# Real module attributes are actually an instance of a C++ object
self._attrA = "a b c d e f".split()
self._attrB = "1 2 3 4 5".split()
def __enter__(self):
self.__init__
return self
def __exit__(self, a,b,c):
self._attrA = None
self._attrB = None
def nAttrA(self):
return len(self._attrA)
def nAttrB(self):
return len(self._attrB)
# Only way to get to AttrA from Python, calls C++ accessor
def getAttrA(self,i):
# real return is as below:
# return _multiAttrObj.get_attr_a(i)
return self._attrA[i] # Example for testing without .pyd
# Only way to get to AttrB from Python, calls C++ accessor
def getAttrB(self,i):
# real return is as below:
# return _multiAttrObj.get_attr_b(i)
return self._attrB[i] # Example for testing without .pyd
# Function can be created, but throws
# TypeError: 'method' object is not subscriptable
# when called like __getitem__
#def AttrA(self,i):
# return self._attrA[i]
#def AttrB(self,i):
# return self._attrB[i]
def __getitem__(self,i):
# This can't distiguish which attribute I want.
pass
编辑: 回答
从 martineau 修改解决方案,我使用了提供的 Sequence 代理,并为了 SWIG 坚持使用属性,因为我无法重新映射 __getattr__ 或 __setattr__。在下面回答sn-p:
def _getAttrAWrap(self):
return SequenceProxy(self.getAttrA, self.nAttrA)
def _getAttrBWrap(self):
return SequenceProxy(self.getAttrB, self.nAttrB)
# Missing setter functions are for future use.
AttrA = property(_getAttrAWrap, "")
AttrB = property(_getAttrBWrap, "")
【问题讨论】:
-
欢迎来到Stack Overflow!您可以发布相关异常的实际堆栈跟踪吗?
-
我很确定你可以(并且应该)让 SWIG 为你处理这个问题。
-
@TemporalWolf:什么例外?本题不涉及任何异常。
-
@TemporalWolf:啊,它被埋在了代码cmets中。
-
你不能让 SWIG 公开将
_attrA和_attrB公开为attrA和attrB吗?与__getitem__混在一起是错误的做法。
标签: python c++ python-3.x swig