विषय पर बढ़ें

अंतिम अद्यतन:2026-10-12

CPython extension development notes

यह लेख हाल में Apache को दिए गए एक feature की पृष्ठभूमि पर चलेगा, CPython में आई समस्याओं पर विस्तार से बात करेंगे, और खुद 0 से एक library लिखने की कोशिश करेंगे, code 星球 पर भी रखा जा चुका है, रुचि रखने वाले download करके सीख सकते हैं।

0. पृष्ठभूमि

हाल में apache arrow को दिया गया एक feature, C++ interface के बदलाव के कारण दूसरी भाषाओं के interfaces में भी बदलाव लाया, कुछ tests भी ठीक करने की ज़रूरत पड़ी।

PyArrow से परिचित लोगों के लिए यह कोई नई बात नहीं, इस बार के interface बदलाव में इस library को भी modify करना पड़ा, क्योंकि दोनों एक ही repository में हैं, वरना ci पास नहीं होता। और PyArrow का implementation CPython से हुआ है, पहले CPython खास नहीं सीखा था, इसलिए ढेर सारी समस्याएँ आईं, जिनमें दो समस्याएँ काफी ज़रूरी थीं, यहाँ note करता हूँ।

समस्या 1: Initialization function के अंदर दूसरी classes के default constructors समर्थित नहीं हैं।

उदाहरण:

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

Error:

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

देखा जा सकता है कि पहचान नहीं हुई, वास्तविक स्थिति में Expression._scalar(True) valid है, हम इसके अंदर का implementation देखते हैं:

@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 type समर्थित है, मुझे शक हुआ कि यह cpython की limitation है, इसलिए नीचे वाले तरीके में बदलने पर काम हो गया:

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

समस्या 2: Definition का order

जब मैंने बाद में बनाए _true का उपयोग किया, तो हर बार पास होने वाला default value खाली था, यह समझने में आसान है, क्योंकि अंत में compile होकर यह एक xxx.cpp फ़ाइल में translate होता है, C++ के नियमों के अनुसार पहले पढ़ा गया value स्वाभाविक रूप से खाली होता है।

def __init__(self, mode="only_valid", filter=_true):
        pass


cdef CExpression _true = CMakeScalarExpression(
    <shared_ptr[CScalar]> make_shared[CBooleanScalar](True)
)

ठीक है, ऊपर की पृष्ठभूमि के आधार पर, मैं भी खुद एक उदाहरण लिखना चाहता हूँ, जैसे: C++ से एक class लिखकर sort और sum wrap करें, फिर Python से call करें।

1. CPython का पूर्ण उदाहरण

  1. एक .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;
}

2) foo.pyx बनाएँ

मुख्य बात: ऊपर वाले vector के लिए चाहिए:

from libcpp.vector cimport vector

फिर एक class define करके, C++ के interface को call करें।

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)
  1. setup.py फ़ाइल बनाएँ
ext = Extension('Foo', sources=["foo.pyx"], language="c++", include_dirs=[numpy.get_include()])

setup(name="Foo", ext_modules = cythonize([ext]))
  1. Run
python3 setup.py build_ext --inplace

अंत में, एक test script लिखकर अपना लिखा python interface उपयोग किया जा सकता है।

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 कुछ projects में काफी उपयोग होता है, सीखना शुरू करें~

Run:

➜  cpython_examples python3 test.py 
Sorted nums: [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5]
Sum of nums: 44

संबंधित विषय

टिप्पणियाँ