当前位置:   article > 正文

开源贡献代码之​探索一下Cython

开源贡献代码之​探索一下Cython

探索一下Cython

本篇文章将会围绕最近给Apache提的一个feature为背景,展开讲讲Cython遇到的问题,以及尝试自己从0写一个库出来,代码也已经放星球了,感兴趣的同学可以去下载学习。

0.背景

最近在给apache arrow提的一个feature因为C++接口的变动引发其他语言的接口变动,一些测试也跟着需要修复。

像PyArrow熟悉的人应该一点也不陌生,这次接口变动也需要修改这个库,因为是在一个仓库里的,不然ci过不了。而PyArrow的实现是通过Cython实现的,之前也没特别学习Cython,改出了一堆问题,其中遇到两个问题比较重要,这里记录一下。

问题1:初始化函数里面不支持其他类的默认构造。

示例:

  1. def __init__(self, mode="only_valid", filter=Expression._scalar(True)):
  2.    pass

报错:

TypeError: descriptor '_scalar' for 'pyarrow._compute.Expression' objects doesn't apply to a 'bool' object

可以看到没识别出来,实际情况是Expression._scalar(True)合法的,我们看里面的实现:

  1. @staticmethod
  2. def _scalar(value):
  3.     cdef:
  4.         Scalar scalar
  5.     if isinstance(value, Scalar):
  6.         scalar = value
  7.     else:
  8.         scalar = lib.scalar(value)
  9.     return Expression.wrap(CMakeScalarExpression(scalar.unwrap()))

可以看到,里面支持正常的bool类型,我怀疑这是cython的限制,于是改为下面这种方式就可以了:

  1. def __init__(self, mode="only_valid", filter=None):
  2.     if filter is None:
  3.         filter = Expression._scalar(True)

问题2:定义顺序

当我使用后面创建的_true,每次传递进去的默认值是空,这个比较好理解,因为最后编译好了会翻译为一个xxx.cpp文件,根据C++规则前面读到的自然就是空了。

  1. def __init__(self, mode="only_valid", filter=_true):
  2.    pass
  3.   
  4. cdef CExpression _true = CMakeScalarExpression(
  5.     <shared_ptr[CScalar]> make_shared[CBooleanScalar](True)
  6. )

好了,基于以上背景,我自己也想写一个例子出来,例如:使用C++写一个类,封装sort和sum,然后使用Python调用。

1.Cython完整例子

  1. 创建一个.h文件

  1. void sort(std::vector<int>& nums) {
  2.     std::sort(nums.begin(), nums.end());
  3. }
  4. int sum(std::vector<int>& nums) {
  5.     int sum = 0;
  6.     for (int num : nums) {
  7.         sum += num;
  8.     }
  9.     return sum;
  10. }
  1. 创建foo.pyx

重要点:上面vector需要:

from libcpp.vector cimport vector

然后去定义一个class,调用C++的接口。

  1. cdef class PyFoo:
  2.     cdef Foo* f
  3.     def __cinit__(self):
  4.         self.f = new Foo()
  5.     def __dealloc__(self):
  6.         del self.f
  7.     def sort(self, nums):
  8.         cdef vector[int] c_nums = nums
  9.         self.f.sort(c_nums)
  10.     def sum(self, nums):
  11.         cdef vector[int] c_nums = nums
  12.         return self.f.sum(c_nums)
  1. 创建setup.py文件

  1. ext = Extension('Foo', sources=["foo.pyx"], language="c++", include_dirs=[numpy.get_include()])
  2. setup(name="Foo", ext_modules = cythonize([ext]))
  1. 运行

python3 setup.py build_ext --inplace

最后,可以写一个测试脚本去使用自己写的python接口。

  1. import Foo
  2. f = Foo.PyFoo()
  3. nums = [31415926535]
  4. f.sort(nums)
  5. print("Sorted nums:", nums)
  6. print("Sum of nums:", f.sum(nums))

Cython在一些项目中使用挺多的,学习起来吧~

运行:

  1. ➜  cpython_examples python3 test.py 
  2. Sorted nums: [31415926535]
  3. Sum of nums: 44

热度更新,手把手实现工业级线程池

0d45e01959e844c0c3aa2b05b4088c1c.jpeg

0ebf387ac57c55280c906b6c7ce615ea.jpeg

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/476756
推荐阅读
相关标签
  

闽ICP备14008679号