Files
CPlusPlusThings/site_extras/cpp-guides-cpython-extension-notes.md
light-city dfe1c933b3 docs: address community issue feedback (#5 #338 #142 #246 #136 #303)
- const README: rewrite the space-saving claim per issue #5 follow-ups
  (constant-expression const vs #define immediates; which const qualify
  as constant expressions)
- const README: fix the class-section diagnosis per issue #338 (overload
  resolution picks the const overload; the restriction only surfaces
  once that overload is removed)
- sizeof README: virtual-inheritance result is compiler-dependent
  (GCC merges vbptr+vfptr -> 16, MSVC keeps them separate -> 32) #246
- static README: new section on internal linkage / access restriction
  with anonymous-namespace comparison #142
- 10-day practice: full problem list table + fixed day links #136
- new design_pattern/singleton/singleton_default.hpp: reusable
  thread-safe CRTP singleton template, compile+concurrency tested #303
2026-10-13 19:23:54 +08:00

148 lines
3.7 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
> 来自 [C++那些事网站](https://light-city.github.io/stories_things/cpp-guides/cpython-extension-notes/) 的文章,由站点同步脚本导出。
# CPython 扩展开发笔记
本篇文章将会围绕最近给Apache提的一个feature为背景,展开讲讲CPython遇到的问题,以及尝试自己从0写一个库出来,代码也已经放星球了,感兴趣的同学可以去下载学习。
## 0.背景
最近在给apache arrow提的一个feature因为C++接口的变动引发其他语言的接口变动,一些测试也跟着需要修复。
像PyArrow熟悉的人应该一点也不陌生,这次接口变动也需要修改这个库,因为是在一个仓库里的,不然ci过不了。而PyArrow的实现是通过CPython实现的,之前也没特别学习CPython,改出了一堆问题,其中遇到两个问题比较重要,这里记录一下。
**问题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)合法的,我们看里面的实现:
```python
@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类型,我怀疑这是cpython的限制,于是改为下面这种方式就可以了:
```python
def __init__(self, mode="only_valid", filter=None):
if filter is None:
filter = Expression._scalar(True)
```
**问题2:定义顺序**
当我使用后面创建的`_true`,每次传递进去的默认值是空,这个比较好理解,因为最后编译好了会翻译为一个`xxx.cpp`文件,根据C++规则前面读到的自然就是空了。
```python
def __init__(self, mode="only_valid", filter=_true):
pass
cdef CExpression _true = CMakeScalarExpression(
<shared_ptr[CScalar]> make_shared[CBooleanScalar](True)
)
```
好了,基于以上背景,我自己也想写一个例子出来,例如:使用C++写一个类,封装sort和sum,然后使用Python调用。
## 1.CPython完整例子
1. 创建一个.h文件
```cpp
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;
}
```
2) 创建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)
```
3. 创建setup.py文件
```python
ext = Extension('Foo', sources=["foo.pyx"], language="c++", include_dirs=[numpy.get_include()])
setup(name="Foo", ext_modules = cythonize([ext]))
```
4. 运行
```
python3 setup.py build_ext --inplace
```
最后,可以写一个测试脚本去使用自己写的python接口。
```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))
```
CPython在一些项目中使用挺多的,学习起来吧~
运行:
```
➜ cpython_examples python3 test.py
Sorted nums: [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5]
Sum of nums: 44
```