V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
Huelse
V2EX  ›  Python

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

  •  
  •   Huelse · 2019-07-22 11:03:46 +08:00 · 2768 次点击
    这是一个创建于 1950 天前的主题,其中的信息可能已经有所发展或是发生改变。

    最近在用 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 方法?

    谢谢各位了!

    21 条回复    2019-07-23 09:19:39 +08:00
    ysc3839
        1
    ysc3839  
       2019-07-22 13:38:56 +08:00 via Android   ❤️ 1
    C++ 这样是返回了引用,我印象中 Python 没有等价的写法吧?建议按 Python 的风格弄成 getter setter。
    Huelse
        2
    Huelse  
    OP
       2019-07-22 13:46:17 +08:00
    @ysc3839 #1 嗯嗯,最后我还是在 Ciphertext 类里增加了一个 set_scale 方法 ,谢谢
    ysc3839
        3
    ysc3839  
       2019-07-22 14:05:24 +08:00 via Android
    @Huelse 并不建议这么做,可以用 def_property 定义成可直接读写的属性。
    https://pybind11.readthedocs.io/en/stable/classes.html#instance-and-static-fields
    另外看文档也许可以试试 def_readwrite ?
    Huelse
        4
    Huelse  
    OP
       2019-07-22 16:19:00 +08:00
    @ysc3839 #3 试过了,不可行,def_property 需要 set 和 get,c++里没有,def_readwrite 会说 scale 是私有的
    guiqiqi
        5
    guiqiqi  
       2019-07-22 16:21:08 +08:00 via iPhone   ❤️ 1
    最近正在用,我不想搞成 python 那种 getter setter 的方法,于是选择了函数重载,也蛮好用的,仅供参考
    Valyrian
        6
    Valyrian  
       2019-07-22 16:22:08 +08:00
    把 int 包成 class 然后返回引用(逃
    Huelse
        7
    Huelse  
    OP
       2019-07-22 16:53:20 +08:00
    @guiqiqi #5 还是要改 c++代码吧?
    guiqiqi
        8
    guiqiqi  
       2019-07-22 17:10:12 +08:00 via iPhone
    @Huelse 对的,得改一下
    ysc3839
        9
    ysc3839  
       2019-07-22 17:45:24 +08:00 via Android
    @Huelse getter setter 当然要自己写呀。
    Huelse
        10
    Huelse  
    OP
       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
        11
    ysc3839  
       2019-07-22 17:52:59 +08:00 via Android
    @Huelse 看上去 destination 是返回值吧?那直接返回就好了吧。
    Huelse
        12
    Huelse  
    OP
       2019-07-22 18:01:52 +08:00
    @ysc3839 #11 我是想不改 c++代码可以吗

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

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

    现在我想在不改变 c++代码的情况下,通过 pybind11 绑定完成 list 变量生成
    Huelse
        15
    Huelse  
    OP
       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
        16
    Huelse  
    OP
       2019-07-23 00:25:59 +08:00
    @ysc3839 #13 我想我大概有办法了,我重新定义了一个 py::class_<DoubleVector>(m, "DoubleVector"),
    现在想怎么把 operator[]加进去,方便 python 里直接 list[123]这样直接索引赋值
    Huelse
        17
    Huelse  
    OP
       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
        18
    guiqiqi  
       2019-07-23 00:34:15 +08:00 via iPhone
    @Huelse 不好意思才看到,我没有读懂你的问题;因为 python 传参数如果是可变量也是引用的,如果你要是要传入 CPP 的函数里,我没这么操作过抱歉帮不到你,但是为什么不在 CPP 里生成好再传出来呢 :) 虽说是胶水语言,但毕竟一层干一层的事情嘛。

    我用的是 boost::python,pybind 看起来像是在其上又封装了一层,绑定机制什么的看起来都一样的。如果 pybind 文档少,你可以查查 boost 的相关资料。
    guiqiqi
        19
    guiqiqi  
       2019-07-23 00:35:50 +08:00 via iPhone   ❤️ 1
    @Huelse 这个我试过,你甚至可以直接定义一个 __hash__ 导出到类里,这样你的自定义 CPP 类就支持了 Python 的 hash 哦 :)
    Huelse
        20
    Huelse  
    OP
       2019-07-23 09:12:54 +08:00
    @guiqiqi #19 我想知道__getitem__,__hash__ 这样怎么写到自定义类里,请问能给个参考吗?
    Huelse
        21
    Huelse  
    OP
       2019-07-23 09:19:39 +08:00
    @guiqiqi #19
    ```
    py::class_<uIntVector>(m, "uIntVector")
    .def("__getitem__", [](const uIntVector &v, int i) {
    return v[i];
    }, py::keep_alive<1, 2>());

    ```
    我这样写可以索引取值了,但还不能赋值,也没考虑切片的情况
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3583 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 04:20 · PVG 12:20 · LAX 20:20 · JFK 23:20
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.