我有一个
std::vector<const T*>
我从c ++函数返回:
getallTs()
我用T:暴露了T类:
class_<T,T*>
和这样的矢量:
class_<std::vector<const T*> >("TsList")
.def(vector_indexing_suite<std::vector<const T*>,true>())
;
NoProxy参数是什么意思?
我公开了这样的函数:
def("getallTs", getallTs,
return_value_policy<return_by_value>{});
我观察到一种奇怪的行为。
当我从python打电话时
tlist = getallTs()
我得到一个TsList对象。
len(tlist)
的工作原理。
tlist[<anycorrectindex>].<someattribute>
也有效。
但是,如果我只是
print(tlist[0])
和
print(tlist[100])
python打印
object T at <address>
此地址对于tlist中的所有Ts都是相同的。
另外,我不能用python for循环迭代Tlist。
for t in tlist:
不起作用。
我将向量和函数暴露给python的方式有什么问题?
我理解每个包装c ++ T的python对象都持有一个指向T的原始指针。 这些T实例在整个过程中存在于全局表中。
c ++函数重新返回指向这些实例的指针向量。 indexing_suite对这些做了什么?
谢谢,
答案 0 :(得分:0)
当通过索引访问元素时,索引套件默认为元素提供代理,作为为Python用户通常期望的集合提供可变类型的引用语义的方法:
val = c[i]
c[i].m() # Mutates state, equivalent to `val.m()`
assert(val == c[i]) # Have same state.
val.m()
assert(val == c[i]) # Have same state.
在上面的示例中,val
是一个知道容器元素的代理对象。当NoProxy
为true
时,会在索引时获取值语义,从而在每个索引访问时生成副本。
val = c[i] # val is a copy.
c[i].m() # Modify a copy of c[i].
assert(val == c[i]) # These have the same state because c[i] returns a new copy.
val.m()
assert(val != c[i]) # These do not have the same state.
当不使用代理时,元素的突变只会在对元素的引用上调用时持续存在,例如在迭代期间:
for val in c:
val.m() # modification observed in c[#]
调用print(c[i])
时,会创建一个临时代理对象并传递给print
,代理对象的生命周期从print()
返回时结束。因此,可以重用临时代理对象使用的存储器和标识。这可能导致元素看起来具有相同的标识:
id0 = id(c[0]) # id of the temporary proxy
id1 = id(c[1]) # id of another temporary proxy
assert(id0 ?? id1) # Non-deterministic if these will be the same.
assert(c[0] is not c[1]) # Guaranteed to not be the same.
另一方面,在代理的生命周期中,同一元素的其他代理将具有相同的标识,并且不同元素的代理将具有不同的标识:
c0 = c[0] # proxy to element 0.
c0_2 = c[0] # another proxy to element 0.
c1 = c[1] # proxy to element 1
assert(c0 is c0_2)
assert(c0 is c[0])
assert(c0 is not c1)
如果T
已被T*
公开,std::vector<const T*>
的情况下,如果const T*
没有to-Python转换,则T
上的迭代将在Python中失败到一个Python对象。公开由T*
持有的类T*
会自动注册const T*
的Python和Python转换,而不是const T*
。在Python中迭代集合时,会返回对元素的引用,导致Python对象无法从std::vector<>
构造。另一方面,当通过索引访问元素时,生成的Python对象是代理或副本,可以使用现有的转换器。要解决此问题,请考虑:
T
的元素类型与const T*
的持有类型List<FooBar> listOfFooBar = foos.stream()
.flatMap(foo -> bars.stream().filter(bar-> bar.getFoo().equals(foo)).findFirst()
.map(Stream::of).orElse(Stream.empty()))
.map(bar -> {
FooBar fooBar = new FooBar();
fooBar.setBar(bar);
return fooBar;
})
.collect(Collectors.toList());
到Python转换器