vector_indexing_suite

时间:2015-09-14 14:47:59

标签: boost-python

我有一个

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对这些做了什么?

谢谢,

1 个答案:

答案 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是一个知道容器元素的代理对象。当NoProxytrue时,会在索引时获取值语义,从而在每个索引访问时生成副本。

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转换器