C++中对函数赋值,怎么在 Python 实现?

2019-07-22 11:03:46 +08:00
 Huelse

最近在用 pybind11 绑定 c++中的一个库到 Python 中,遇到了一个问题

待绑定的类方法如下

class Ciphertext
{
public:
    inline auto &scale() noexcept
    {
        return scale_;
    }

    inline auto &scale() const noexcept
    {
        return scale_;
    }

    private:
        double scale_ = 1.0;
}

其例子中,有这样的调用:

Ciphertext x1_encrypted
x1_encrypted.scale() = pow(2.0, 40)

我是这样绑定的,可以成功访问到 scale 的值:

py::class_<Ciphertext>(m, "Ciphertext")
    .def("scale", (double &(Ciphertext::*)()) &Ciphertext::scale)

但是,显然不能这样在 python 中给它赋值,请问有什么方法?还是说,只能自己去增加 set 方法?

谢谢各位了!

2786 次点击
所在节点    Python
21 条回复
ysc3839
2019-07-22 13:38:56 +08:00
C++ 这样是返回了引用,我印象中 Python 没有等价的写法吧?建议按 Python 的风格弄成 getter setter。
Huelse
2019-07-22 13:46:17 +08:00
@ysc3839 #1 嗯嗯,最后我还是在 Ciphertext 类里增加了一个 set_scale 方法 ,谢谢
ysc3839
2019-07-22 14:05:24 +08:00
@Huelse 并不建议这么做,可以用 def_property 定义成可直接读写的属性。
https://pybind11.readthedocs.io/en/stable/classes.html#instance-and-static-fields
另外看文档也许可以试试 def_readwrite ?
Huelse
2019-07-22 16:19:00 +08:00
@ysc3839 #3 试过了,不可行,def_property 需要 set 和 get,c++里没有,def_readwrite 会说 scale 是私有的
guiqiqi
2019-07-22 16:21:08 +08:00
最近正在用,我不想搞成 python 那种 getter setter 的方法,于是选择了函数重载,也蛮好用的,仅供参考
Valyrian
2019-07-22 16:22:08 +08:00
把 int 包成 class 然后返回引用(逃
Huelse
2019-07-22 16:53:20 +08:00
@guiqiqi #5 还是要改 c++代码吧?
guiqiqi
2019-07-22 17:10:12 +08:00
@Huelse 对的,得改一下
ysc3839
2019-07-22 17:45:24 +08:00
@Huelse getter setter 当然要自己写呀。
Huelse
2019-07-22 17:48:50 +08:00
@ysc3839 #9 嗯嗯,了解,我现在想另一个问题

@guiqiqi #8 想请你们看下

```
template<typename T,
typename = std::enable_if_t<std::is_same<T, double>::value ||
std::is_same<T, std::complex<double>>::value>>
inline void decode(const Plaintext &plain, std::vector<T> &destination,
MemoryPoolHandle pool = MemoryManager::GetPool())
{
decode_internal(plain, destination, std::move(pool));
}
```
这种 template 怎么绑定
是参照这个嘛?

https://github.com/pybind/pybind11/blob/master/tests/test_opaque_types.cpp

https://github.com/pybind/pybind11/issues/1854
ysc3839
2019-07-22 17:52:59 +08:00
@Huelse 看上去 destination 是返回值吧?那直接返回就好了吧。
Huelse
2019-07-22 18:01:52 +08:00
@ysc3839 #11 我是想不改 c++代码可以吗

destination = []
func(destination) { ... }
destination = [...]

类似于这样
ysc3839
2019-07-22 18:09:53 +08:00
@Huelse 什么意思?
Huelse
2019-07-22 22:05:01 +08:00
@ysc3839 #13
就是我 list 变量放进函数里进行操作,按照 Python 的内存管理,显然不会对函数外的 list 产生影响

现在我想在不改变 c++代码的情况下,通过 pybind11 绑定完成 list 变量生成
Huelse
2019-07-22 22:12:00 +08:00
@ysc3839 #13 按文档里说的,应该是声明 std::vector<double>opaque 类型就可以了
https://pybind11.readthedocs.io/en/stable/advanced/cast/stl.html
但是,我不知道为啥,还是不行。
Huelse
2019-07-23 00:25:59 +08:00
@ysc3839 #13 我想我大概有办法了,我重新定义了一个 py::class_<DoubleVector>(m, "DoubleVector"),
现在想怎么把 operator[]加进去,方便 python 里直接 list[123]这样直接索引赋值
Huelse
2019-07-23 00:26:33 +08:00
@ysc3839 #13 我想我大概有办法了,我重新定义了一个 PYBIND11_MAKE_OPAQUE(std::vector<double>); py::class_<DoubleVector>(m, "DoubleVector"),
现在想怎么把 operator[] 加进去,方便 python 里直接 list[123]这样直接索引赋值
guiqiqi
2019-07-23 00:34:15 +08:00
@Huelse 不好意思才看到,我没有读懂你的问题;因为 python 传参数如果是可变量也是引用的,如果你要是要传入 CPP 的函数里,我没这么操作过抱歉帮不到你,但是为什么不在 CPP 里生成好再传出来呢 :) 虽说是胶水语言,但毕竟一层干一层的事情嘛。

我用的是 boost::python,pybind 看起来像是在其上又封装了一层,绑定机制什么的看起来都一样的。如果 pybind 文档少,你可以查查 boost 的相关资料。
guiqiqi
2019-07-23 00:35:50 +08:00
@Huelse 这个我试过,你甚至可以直接定义一个 __hash__ 导出到类里,这样你的自定义 CPP 类就支持了 Python 的 hash 哦 :)
Huelse
2019-07-23 09:12:54 +08:00
@guiqiqi #19 我想知道__getitem__,__hash__ 这样怎么写到自定义类里,请问能给个参考吗?

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/585022

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX