赞
踩
本篇文章将会围绕最近给Apache提的一个feature为背景,展开讲讲Cython遇到的问题,以及尝试自己从0写一个库出来,代码也已经放星球了,感兴趣的同学可以去下载学习。
最近在给apache arrow提的一个feature因为C++接口的变动引发其他语言的接口变动,一些测试也跟着需要修复。
像PyArrow熟悉的人应该一点也不陌生,这次接口变动也需要修改这个库,因为是在一个仓库里的,不然ci过不了。而PyArrow的实现是通过Cython实现的,之前也没特别学习Cython,改出了一堆问题,其中遇到两个问题比较重要,这里记录一下。
问题1:初始化函数里面不支持其他类的默认构造。
示例:
- def __init__(self, mode="only_valid", filter=Expression._scalar(True)):
- pass
报错:
TypeError: descriptor '_scalar' for 'pyarrow._compute.Expression' objects doesn't apply to a 'bool' object
可以看到没识别出来,实际情况是Expression._scalar(True)合法的,我们看里面的实现:
- @staticmethod
- def _scalar(value):
- cdef:
- Scalar scalar
-
- if isinstance(value, Scalar):
- scalar = value
- else:
- scalar = lib.scalar(value)
-
- return Expression.wrap(CMakeScalarExpression(scalar.unwrap()))
可以看到,里面支持正常的bool类型,我怀疑这是cython的限制,于是改为下面这种方式就可以了:
- def __init__(self, mode="only_valid", filter=None):
- if filter is None:
- filter = Expression._scalar(True)
问题2:定义顺序
当我使用后面创建的_true
,每次传递进去的默认值是空,这个比较好理解,因为最后编译好了会翻译为一个xxx.cpp
文件,根据C++规则前面读到的自然就是空了。
- def __init__(self, mode="only_valid", filter=_true):
- pass
-
-
- cdef CExpression _true = CMakeScalarExpression(
- <shared_ptr[CScalar]> make_shared[CBooleanScalar](True)
- )
好了,基于以上背景,我自己也想写一个例子出来,例如:使用C++写一个类,封装sort和sum,然后使用Python调用。
创建一个.h文件
- void sort(std::vector<int>& nums) {
- std::sort(nums.begin(), nums.end());
- }
- int sum(std::vector<int>& nums) {
- int sum = 0;
- for (int num : nums) {
- sum += num;
- }
- return sum;
- }
创建foo.pyx
重要点:上面vector需要:
from libcpp.vector cimport vector
然后去定义一个class,调用C++的接口。
- cdef class PyFoo:
- cdef Foo* f
-
- def __cinit__(self):
- self.f = new Foo()
-
- def __dealloc__(self):
- del self.f
-
- def sort(self, nums):
- cdef vector[int] c_nums = nums
- self.f.sort(c_nums)
-
- def sum(self, nums):
- cdef vector[int] c_nums = nums
- return self.f.sum(c_nums)
创建setup.py文件
- ext = Extension('Foo', sources=["foo.pyx"], language="c++", include_dirs=[numpy.get_include()])
-
- setup(name="Foo", ext_modules = cythonize([ext]))
运行
python3 setup.py build_ext --inplace
最后,可以写一个测试脚本去使用自己写的python接口。
- import Foo
-
- f = Foo.PyFoo()
- nums = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5]
- f.sort(nums)
- print("Sorted nums:", nums)
- print("Sum of nums:", f.sum(nums))
Cython在一些项目中使用挺多的,学习起来吧~
运行:
- ➜ cpython_examples python3 test.py
- Sorted nums: [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5]
- Sum of nums: 44
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。