Python中如何实现类似C++中对函数赋值的功能?
最近在用 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 方法?
谢谢各位了!
Python中如何实现类似C++中对函数赋值的功能?
C++ 这样是返回了引用,我印象中 Python 没有等价的写法吧?建议按 Python 的风格弄成 getter setter。
在Python里,你想直接像C++那样给函数赋值(比如 void (*funcPtr)(int) = someFunction;)是行不通的,因为Python的函数名本身就是引用。不过,你想达到的效果——动态地改变一个函数名指向的代码块——用Python实现起来更简单直接。
核心就一点:在Python中,函数名只是一个变量,它存储了对一个函数对象的引用。 所以,所谓的“函数赋值”,其实就是普通的变量赋值。
看个例子就全明白了:
def original_function(x):
return x * 2
def new_function(x):
return x ** 2
# 现在,`my_func` 这个变量指向了 `original_function`
my_func = original_function
print(my_func(5)) # 输出: 10
# 这就是你要的“函数赋值”:让 `my_func` 改为指向 `new_function`
my_func = new_function
print(my_func(5)) # 输出: 25
# 你甚至可以把它指向一个 lambda 表达式(匿名函数)
my_func = lambda x: x + 100
print(my_func(5)) # 输出: 105
如果你想模拟C++里函数指针作为参数传递的场景:
def processor(data, func):
"""接收一个函数`func`作为参数,并应用到`data`上"""
return func(data)
def double(x):
return x * 2
def square(x):
return x * x
result1 = processor(10, double) # 传递 double 函数
print(result1) # 输出: 20
result2 = processor(10, square) # 传递 square 函数
print(result2) # 输出: 100
更高级点,你可以把函数放在列表或字典里,实现一个简单的“函数表”或分发器:
def op_add(a, b):
return a + b
def op_subtract(a, b):
return a - b
# 函数字典
operation_map = {
'add': op_add,
'subtract': op_subtract,
'multiply': lambda a, b: a * b # 直接内联lambda
}
# 使用
command = 'multiply'
func_to_call = operation_map[command]
result = func_to_call(5, 3)
print(result) # 输出: 15
总结一下: 在Python里,直接把函数当变量用就行,赋值、传参、放进容器里,怎么都行,比C++的函数指针直观多了。
一句话建议: 在Python中,把函数当作普通对象进行赋值和传递即可实现类似功能。
#1 嗯嗯,最后我还是在 Ciphertext 类里增加了一个 set_scale 方法
,谢谢
并不建议这么做,可以用 def_property 定义成可直接读写的属性。
https://pybind11.readthedocs.io/en/stable/classes.html#instance-and-static-fields
另外看文档也许可以试试 def_readwrite ?
#3 试过了,不可行,def_property 需要 set 和 get,c++里没有,def_readwrite 会说 scale 是私有的
最近正在用,我不想搞成 python 那种 getter setter 的方法,于是选择了函数重载,也蛮好用的,仅供参考
把 int 包成 class 然后返回引用(逃
#5 还是要改 c++代码吧?
对的,得改一下
getter setter 当然要自己写呀。
#9 嗯嗯,了解,我现在想另一个问题
#8 想请你们看下<br>template<typename T,<br> typename = std::enable_if_t<std::is_same<T, double>::value ||<br> std::is_same<T, std::complex<double>>::value>><br> inline void decode(const Plaintext &plain, std::vector<T> &destination,<br> MemoryPoolHandle pool = MemoryManager::GetPool())<br> {<br> decode_internal(plain, destination, std::move(pool));<br> }<br>
这种 template 怎么绑定
是参照这个嘛?
https://github.com/pybind/pybind11/blob/master/tests/test_opaque_types.cpp
https://github.com/pybind/pybind11/issues/1854
看上去 destination 是返回值吧?那直接返回就好了吧。
#11 我是想不改 c++代码可以吗
destination = []
func(destination) { … }
destination = […]
类似于这样
什么意思?
#13
就是我 list 变量放进函数里进行操作,按照 Python 的内存管理,显然不会对函数外的 list 产生影响
现在我想在不改变 c++代码的情况下,通过 pybind11 绑定完成 list 变量生成
#13 按文档里说的,应该是声明 std::vector<double>opaque 类型就可以了
https://pybind11.readthedocs.io/en/stable/advanced/cast/stl.html
但是,我不知道为啥,还是不行。
#13 我想我大概有办法了,我重新定义了一个 py::class_<DoubleVector>(m, “DoubleVector”),
现在想怎么把 operator[]加进去,方便 python 里直接 list[123]这样直接索引赋值
#13 我想我大概有办法了,我重新定义了一个 PYBIND11_MAKE_OPAQUE(std::vector<double>); py::class_<DoubleVector>(m, “DoubleVector”),
现在想怎么把 operator[] 加进去,方便 python 里直接 list[123]这样直接索引赋值
不好意思才看到,我没有读懂你的问题;因为 python 传参数如果是可变量也是引用的,如果你要是要传入 CPP 的函数里,我没这么操作过抱歉帮不到你,但是为什么不在 CPP 里生成好再传出来呢 :) 虽说是胶水语言,但毕竟一层干一层的事情嘛。
我用的是 boost::python,pybind 看起来像是在其上又封装了一层,绑定机制什么的看起来都一样的。如果 pybind 文档少,你可以查查 boost 的相关资料。
这个我试过,你甚至可以直接定义一个 hash 导出到类里,这样你的自定义 CPP 类就支持了 Python 的 hash 哦 :)
#19 我想知道__getitem__,hash 这样怎么写到自定义类里,请问能给个参考吗?
#19 <br>py::class_<uIntVector>(m, "uIntVector")<br> .def("__getitem__", [](const uIntVector &v, int i) {<br> return v[i];<br> }, py::keep_alive<1, 2>());<br><br>
我这样写可以索引取值了,但还不能赋值,也没考虑切片的情况 

