Added sample files generated on the three different scenarios.
Including C code, setup.py and run example code for: * Pi calculation with Leibniz formula. * Max sub-array calculation. (Aka: Python Hard) * Default for Gradio: Hello world. (Aka: _zz_my_module)
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
#define PY_SSIZE_T_CLEAN
|
||||
#include <Python.h>
|
||||
#include <math.h>
|
||||
#include <float.h>
|
||||
#include <limits.h>
|
||||
#include <stdint.h>
|
||||
|
||||
static PyObject* leibniz_pi(PyObject* self, PyObject* args) {
|
||||
PyObject* iterations_obj;
|
||||
if (!PyArg_ParseTuple(args, "O", &iterations_obj)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
long long n_signed;
|
||||
int overflow = 0;
|
||||
n_signed = PyLong_AsLongLongAndOverflow(iterations_obj, &overflow);
|
||||
if (n_signed == -1 && PyErr_Occurred() && overflow == 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
unsigned long long n = 0ULL;
|
||||
if (overflow < 0) {
|
||||
n = 0ULL;
|
||||
} else if (overflow > 0) {
|
||||
unsigned long long tmp = PyLong_AsUnsignedLongLong(iterations_obj);
|
||||
if (tmp == (unsigned long long)-1 && PyErr_Occurred()) {
|
||||
return NULL;
|
||||
}
|
||||
n = tmp;
|
||||
} else {
|
||||
if (n_signed <= 0) {
|
||||
n = 0ULL;
|
||||
} else {
|
||||
n = (unsigned long long)n_signed;
|
||||
}
|
||||
}
|
||||
|
||||
double result = 1.0;
|
||||
if (n == 0ULL) {
|
||||
return PyFloat_FromDouble(result * 4.0);
|
||||
}
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
for (unsigned long long i = 1ULL; i <= n; ++i) {
|
||||
double jd1;
|
||||
if (i <= ULLONG_MAX / 4ULL) {
|
||||
unsigned long long j1 = i * 4ULL - 1ULL;
|
||||
jd1 = (double)j1;
|
||||
} else {
|
||||
jd1 = (double)i * 4.0 - 1.0;
|
||||
}
|
||||
result -= 1.0 / jd1;
|
||||
|
||||
double jd2;
|
||||
if (i <= (ULLONG_MAX - 1ULL) / 4ULL) {
|
||||
unsigned long long j2 = i * 4ULL + 1ULL;
|
||||
jd2 = (double)j2;
|
||||
} else {
|
||||
jd2 = (double)i * 4.0 + 1.0;
|
||||
}
|
||||
result += 1.0 / jd2;
|
||||
}
|
||||
Py_END_ALLOW_THREADS
|
||||
|
||||
return PyFloat_FromDouble(result * 4.0);
|
||||
}
|
||||
|
||||
static PyMethodDef CalculatePiMethods[] = {
|
||||
{"leibniz_pi", leibniz_pi, METH_VARARGS, "Compute pi using the Leibniz series with the given number of iterations."},
|
||||
{NULL, NULL, 0, NULL}
|
||||
};
|
||||
|
||||
static struct PyModuleDef calculate_pimodule = {
|
||||
PyModuleDef_HEAD_INIT,
|
||||
"calculate_pi",
|
||||
"High-performance Leibniz pi calculation.",
|
||||
-1,
|
||||
CalculatePiMethods
|
||||
};
|
||||
|
||||
PyMODINIT_FUNC PyInit_calculate_pi(void) {
|
||||
return PyModule_Create(&calculate_pimodule);
|
||||
}
|
||||
@@ -0,0 +1,244 @@
|
||||
#include <Python.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
#include <math.h>
|
||||
|
||||
// LCG step with 32-bit wrap-around
|
||||
static inline uint32_t lcg_next(uint32_t *state) {
|
||||
*state = (uint32_t)(1664525u * (*state) + 1013904223u);
|
||||
return *state;
|
||||
}
|
||||
|
||||
static inline int add_overflow_int64(int64_t a, int64_t b, int64_t *res) {
|
||||
if ((b > 0 && a > INT64_MAX - b) || (b < 0 && a < INT64_MIN - b)) return 1;
|
||||
*res = a + b;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Kadane for int64 array with overflow detection; returns PyLong or NULL (on overflow -> signal via *overflowed)
|
||||
static PyObject* kadane_int64(const int64_t *arr, Py_ssize_t n, int *overflowed) {
|
||||
if (n <= 0) {
|
||||
return PyFloat_FromDouble(-INFINITY);
|
||||
}
|
||||
int64_t meh = arr[0];
|
||||
int64_t msf = arr[0];
|
||||
for (Py_ssize_t i = 1; i < n; ++i) {
|
||||
int64_t x = arr[i];
|
||||
if (meh > 0) {
|
||||
int64_t tmp;
|
||||
if (add_overflow_int64(meh, x, &tmp)) { *overflowed = 1; return NULL; }
|
||||
meh = tmp;
|
||||
} else {
|
||||
meh = x;
|
||||
}
|
||||
if (meh > msf) msf = meh;
|
||||
}
|
||||
return PyLong_FromLongLong(msf);
|
||||
}
|
||||
|
||||
// Kadane for PyObject* integer array
|
||||
static PyObject* kadane_big(PyObject **arr, Py_ssize_t n) {
|
||||
if (n <= 0) {
|
||||
return PyFloat_FromDouble(-INFINITY);
|
||||
}
|
||||
PyObject *meh = arr[0]; Py_INCREF(meh);
|
||||
PyObject *msf = arr[0]; Py_INCREF(msf);
|
||||
PyObject *zero = PyLong_FromLong(0);
|
||||
if (!zero) { Py_DECREF(meh); Py_DECREF(msf); return NULL; }
|
||||
|
||||
for (Py_ssize_t i = 1; i < n; ++i) {
|
||||
int cmp = PyObject_RichCompareBool(meh, zero, Py_GT);
|
||||
if (cmp < 0) { Py_DECREF(meh); Py_DECREF(msf); Py_DECREF(zero); return NULL; }
|
||||
if (cmp == 1) {
|
||||
PyObject *t = PyNumber_Add(meh, arr[i]);
|
||||
if (!t) { Py_DECREF(meh); Py_DECREF(msf); Py_DECREF(zero); return NULL; }
|
||||
Py_DECREF(meh);
|
||||
meh = t;
|
||||
} else {
|
||||
Py_DECREF(meh);
|
||||
meh = arr[i]; Py_INCREF(meh);
|
||||
}
|
||||
int cmp2 = PyObject_RichCompareBool(meh, msf, Py_GT);
|
||||
if (cmp2 < 0) { Py_DECREF(meh); Py_DECREF(msf); Py_DECREF(zero); return NULL; }
|
||||
if (cmp2 == 1) {
|
||||
Py_DECREF(msf);
|
||||
msf = meh; Py_INCREF(msf);
|
||||
}
|
||||
}
|
||||
Py_DECREF(meh);
|
||||
Py_DECREF(zero);
|
||||
return msf; // new reference
|
||||
}
|
||||
|
||||
// Generate int64 array fast path; returns 0 on success
|
||||
static int gen_array_int64(Py_ssize_t n, uint32_t seed, int64_t min_v, int64_t max_v, int64_t *out) {
|
||||
uint32_t state = seed;
|
||||
uint64_t umax = (uint64_t)max_v;
|
||||
uint64_t umin = (uint64_t)min_v;
|
||||
uint64_t range = (umax - umin) + 1ULL; // max>=min guaranteed by caller
|
||||
for (Py_ssize_t i = 0; i < n; ++i) {
|
||||
state = lcg_next(&state);
|
||||
uint32_t r32 = state;
|
||||
uint64_t r = (range > 0x100000000ULL) ? (uint64_t)r32 : ((uint64_t)r32 % range);
|
||||
int64_t val = (int64_t)(min_v + (int64_t)r);
|
||||
out[i] = val;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Generate PyObject* int array general path using Python arithmetic
|
||||
static PyObject** gen_array_big(Py_ssize_t n, uint32_t seed, PyObject *min_val, PyObject *max_val) {
|
||||
PyObject **arr = (PyObject**)PyMem_Malloc((n > 0 ? n : 1) * sizeof(PyObject*));
|
||||
if (!arr) {
|
||||
PyErr_NoMemory();
|
||||
return NULL;
|
||||
}
|
||||
PyObject *one = PyLong_FromLong(1);
|
||||
if (!one) { PyMem_Free(arr); return NULL; }
|
||||
PyObject *diff = PyNumber_Subtract(max_val, min_val);
|
||||
if (!diff) { Py_DECREF(one); PyMem_Free(arr); return NULL; }
|
||||
PyObject *range_obj = PyNumber_Add(diff, one);
|
||||
Py_DECREF(diff);
|
||||
Py_DECREF(one);
|
||||
if (!range_obj) { PyMem_Free(arr); return NULL; }
|
||||
|
||||
uint32_t state = seed;
|
||||
for (Py_ssize_t i = 0; i < n; ++i) {
|
||||
state = lcg_next(&state);
|
||||
PyObject *v = PyLong_FromUnsignedLong((unsigned long)state);
|
||||
if (!v) {
|
||||
Py_DECREF(range_obj);
|
||||
for (Py_ssize_t k = 0; k < i; ++k) Py_DECREF(arr[k]);
|
||||
PyMem_Free(arr);
|
||||
return NULL;
|
||||
}
|
||||
PyObject *r = PyNumber_Remainder(v, range_obj);
|
||||
Py_DECREF(v);
|
||||
if (!r) {
|
||||
Py_DECREF(range_obj);
|
||||
for (Py_ssize_t k = 0; k < i; ++k) Py_DECREF(arr[k]);
|
||||
PyMem_Free(arr);
|
||||
return NULL;
|
||||
}
|
||||
PyObject *val = PyNumber_Add(r, min_val);
|
||||
Py_DECREF(r);
|
||||
if (!val) {
|
||||
Py_DECREF(range_obj);
|
||||
for (Py_ssize_t k = 0; k < i; ++k) Py_DECREF(arr[k]);
|
||||
PyMem_Free(arr);
|
||||
return NULL;
|
||||
}
|
||||
arr[i] = val;
|
||||
}
|
||||
Py_DECREF(range_obj);
|
||||
return arr;
|
||||
}
|
||||
|
||||
static PyObject* max_subarray_sum_internal(Py_ssize_t n, uint32_t seed, PyObject *min_val, PyObject *max_val) {
|
||||
if (n <= 0) {
|
||||
return PyFloat_FromDouble(-INFINITY);
|
||||
}
|
||||
|
||||
if (PyLong_Check(min_val) && PyLong_Check(max_val)) {
|
||||
int overflow1 = 0, overflow2 = 0;
|
||||
long long min64 = PyLong_AsLongLongAndOverflow(min_val, &overflow1);
|
||||
if (overflow1) goto BIGINT_PATH;
|
||||
long long max64 = PyLong_AsLongLongAndOverflow(max_val, &overflow2);
|
||||
if (overflow2) goto BIGINT_PATH;
|
||||
if (max64 >= min64) {
|
||||
int64_t *arr = (int64_t*)PyMem_Malloc((size_t)n * sizeof(int64_t));
|
||||
if (!arr) { PyErr_NoMemory(); return NULL; }
|
||||
if (gen_array_int64(n, seed, (int64_t)min64, (int64_t)max64, arr) != 0) {
|
||||
PyMem_Free(arr);
|
||||
return NULL;
|
||||
}
|
||||
int overflowed = 0;
|
||||
PyObject *res = kadane_int64(arr, n, &overflowed);
|
||||
if (!res && overflowed) {
|
||||
// fallback to big-int Kadane
|
||||
PyObject **arr_obj = (PyObject**)PyMem_Malloc((size_t)n * sizeof(PyObject*));
|
||||
if (!arr_obj) { PyMem_Free(arr); PyErr_NoMemory(); return NULL; }
|
||||
for (Py_ssize_t i = 0; i < n; ++i) {
|
||||
arr_obj[i] = PyLong_FromLongLong(arr[i]);
|
||||
if (!arr_obj[i]) {
|
||||
for (Py_ssize_t k = 0; k < i; ++k) Py_DECREF(arr_obj[k]);
|
||||
PyMem_Free(arr_obj);
|
||||
PyMem_Free(arr);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
PyObject *bires = kadane_big(arr_obj, n);
|
||||
for (Py_ssize_t i = 0; i < n; ++i) Py_DECREF(arr_obj[i]);
|
||||
PyMem_Free(arr_obj);
|
||||
PyMem_Free(arr);
|
||||
return bires;
|
||||
}
|
||||
PyMem_Free(arr);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
BIGINT_PATH: ;
|
||||
PyObject **arr_obj = gen_array_big(n, seed, min_val, max_val);
|
||||
if (!arr_obj) return NULL;
|
||||
PyObject *res = kadane_big(arr_obj, n);
|
||||
for (Py_ssize_t i = 0; i < n; ++i) Py_DECREF(arr_obj[i]);
|
||||
PyMem_Free(arr_obj);
|
||||
return res;
|
||||
}
|
||||
|
||||
static PyObject* py_max_subarray_sum(PyObject *self, PyObject *args) {
|
||||
Py_ssize_t n;
|
||||
PyObject *seed_obj, *min_val, *max_val;
|
||||
if (!PyArg_ParseTuple(args, "nOOO", &n, &seed_obj, &min_val, &max_val)) return NULL;
|
||||
if (n < 0) n = 0;
|
||||
uint32_t seed = (uint32_t)(PyLong_AsUnsignedLongLongMask(seed_obj) & 0xFFFFFFFFULL);
|
||||
if (PyErr_Occurred()) return NULL;
|
||||
return max_subarray_sum_internal(n, seed, min_val, max_val);
|
||||
}
|
||||
|
||||
static PyObject* py_total_max_subarray_sum(PyObject *self, PyObject *args) {
|
||||
Py_ssize_t n;
|
||||
PyObject *init_seed_obj, *min_val, *max_val;
|
||||
if (!PyArg_ParseTuple(args, "nOOO", &n, &init_seed_obj, &min_val, &max_val)) return NULL;
|
||||
if (n < 0) n = 0;
|
||||
uint32_t state = (uint32_t)(PyLong_AsUnsignedLongLongMask(init_seed_obj) & 0xFFFFFFFFULL);
|
||||
if (PyErr_Occurred()) return NULL;
|
||||
|
||||
PyObject *total = PyLong_FromLong(0);
|
||||
if (!total) return NULL;
|
||||
|
||||
for (int i = 0; i < 20; ++i) {
|
||||
uint32_t seed = lcg_next(&state);
|
||||
PyObject *part = max_subarray_sum_internal(n, seed, min_val, max_val);
|
||||
if (!part) { Py_DECREF(total); return NULL; }
|
||||
PyObject *new_total = PyNumber_Add(total, part);
|
||||
Py_DECREF(part);
|
||||
if (!new_total) { Py_DECREF(total); return NULL; }
|
||||
Py_DECREF(total);
|
||||
total = new_total;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
static PyMethodDef module_methods[] = {
|
||||
{"max_subarray_sum", (PyCFunction)py_max_subarray_sum, METH_VARARGS, "Compute maximum subarray sum using LCG-generated array."},
|
||||
{"total_max_subarray_sum", (PyCFunction)py_total_max_subarray_sum, METH_VARARGS, "Compute total of maximum subarray sums over 20 LCG seeds."},
|
||||
{NULL, NULL, 0, NULL}
|
||||
};
|
||||
|
||||
static struct PyModuleDef moduledef = {
|
||||
PyModuleDef_HEAD_INIT,
|
||||
"python_hard",
|
||||
NULL,
|
||||
-1,
|
||||
module_methods,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
PyMODINIT_FUNC PyInit_python_hard(void) {
|
||||
return PyModule_Create(&moduledef);
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
from setuptools import setup, Extension
|
||||
import sys
|
||||
import os
|
||||
|
||||
extra_compile_args = []
|
||||
extra_link_args = []
|
||||
|
||||
if os.name == 'nt':
|
||||
extra_compile_args.extend(['/O2', '/fp:precise'])
|
||||
else:
|
||||
extra_compile_args.extend(['-O3', '-fno-strict-aliasing'])
|
||||
|
||||
module = Extension(
|
||||
'calculate_pi',
|
||||
sources=['calculate_pi.c'],
|
||||
extra_compile_args=extra_compile_args,
|
||||
extra_link_args=extra_link_args,
|
||||
)
|
||||
|
||||
setup(
|
||||
name='calculate_pi',
|
||||
version='1.0.0',
|
||||
description='High-performance C extension for computing pi via the Leibniz series',
|
||||
ext_modules=[module],
|
||||
)
|
||||
@@ -0,0 +1,25 @@
|
||||
from setuptools import setup, Extension
|
||||
import sys
|
||||
|
||||
extra_compile_args = []
|
||||
extra_link_args = []
|
||||
if sys.platform == 'win32':
|
||||
extra_compile_args = ['/O2', '/Ot', '/GL', '/fp:fast']
|
||||
extra_link_args = ['/LTCG']
|
||||
else:
|
||||
extra_compile_args = ['-O3', '-march=native']
|
||||
|
||||
module = Extension(
|
||||
name='python_hard',
|
||||
sources=['python_hard.c'],
|
||||
extra_compile_args=extra_compile_args,
|
||||
extra_link_args=extra_link_args,
|
||||
language='c'
|
||||
)
|
||||
|
||||
setup(
|
||||
name='python_hard',
|
||||
version='1.0.0',
|
||||
description='High-performance C extension reimplementation',
|
||||
ext_modules=[module]
|
||||
)
|
||||
@@ -0,0 +1,14 @@
|
||||
|
||||
from setuptools import setup, Extension
|
||||
|
||||
module = Extension(
|
||||
'zz_my_module',
|
||||
sources=['zz_my_module.c'],
|
||||
)
|
||||
|
||||
setup(
|
||||
name='zz_my_module',
|
||||
version='1.0',
|
||||
description='This is a custom C extension module.',
|
||||
ext_modules=[module]
|
||||
)
|
||||
@@ -0,0 +1,38 @@
|
||||
# Build first: python setup.py build_ext --inplace
|
||||
import time
|
||||
import math
|
||||
import calculate_pi
|
||||
|
||||
# Original Python implementation
|
||||
def py_leibniz_pi(iterations):
|
||||
result = 1.0
|
||||
for i in range(1, iterations + 1):
|
||||
j = i * 4 - 1
|
||||
result -= (1 / j)
|
||||
j = i * 4 + 1
|
||||
result += (1 / j)
|
||||
return result * 4
|
||||
|
||||
iters = 5_000_000
|
||||
|
||||
# Warm-up
|
||||
calculate_pi.leibniz_pi(10)
|
||||
py_leibniz_pi(10)
|
||||
|
||||
start = time.perf_counter()
|
||||
res_c = calculate_pi.leibniz_pi(iters)
|
||||
end = time.perf_counter()
|
||||
ctime = end - start
|
||||
|
||||
start = time.perf_counter()
|
||||
res_py = py_leibniz_pi(iters)
|
||||
end = time.perf_counter()
|
||||
pytime = end - start
|
||||
|
||||
print(f"Iterations: {iters}")
|
||||
print(f"C extension result: {res_c}")
|
||||
print(f"Python result: {res_py}")
|
||||
print(f"Absolute difference: {abs(res_c - res_py)}")
|
||||
print(f"C extension time: {ctime:.6f} s")
|
||||
print(f"Python time: {pytime:.6f} s")
|
||||
print(f"Speedup: {pytime/ctime if ctime > 0 else float('inf'):.2f}x")
|
||||
@@ -0,0 +1,69 @@
|
||||
import time
|
||||
|
||||
# Original Python code
|
||||
|
||||
def lcg(seed, a=1664525, c=1013904223, m=2**32):
|
||||
value = seed
|
||||
while True:
|
||||
value = (a * value + c) % m
|
||||
yield value
|
||||
|
||||
def max_subarray_sum_py(n, seed, min_val, max_val):
|
||||
lcg_gen = lcg(seed)
|
||||
random_numbers = [next(lcg_gen) % (max_val - min_val + 1) + min_val for _ in range(n)]
|
||||
max_sum = float('-inf')
|
||||
for i in range(n):
|
||||
current_sum = 0
|
||||
for j in range(i, n):
|
||||
current_sum += random_numbers[j]
|
||||
if current_sum > max_sum:
|
||||
max_sum = current_sum
|
||||
return max_sum
|
||||
|
||||
def total_max_subarray_sum_py(n, initial_seed, min_val, max_val):
|
||||
total_sum = 0
|
||||
lcg_gen = lcg(initial_seed)
|
||||
for _ in range(20):
|
||||
seed = next(lcg_gen)
|
||||
total_sum += max_subarray_sum_py(n, seed, min_val, max_val)
|
||||
return total_sum
|
||||
|
||||
# Build and import extension (after running: python setup.py build && install or develop)
|
||||
import python_hard as ext
|
||||
|
||||
# Example parameters
|
||||
n = 600
|
||||
initial_seed = 12345678901234567890
|
||||
min_val = -1000
|
||||
max_val = 1000
|
||||
|
||||
# Time Python
|
||||
t0 = time.perf_counter()
|
||||
py_res1 = max_subarray_sum_py(n, (initial_seed * 1664525 + 1013904223) % (2**32), min_val, max_val)
|
||||
t1 = time.perf_counter()
|
||||
py_time1 = t1 - t0
|
||||
|
||||
# Time C extension
|
||||
t0 = time.perf_counter()
|
||||
ext_res1 = ext.max_subarray_sum(n, (initial_seed * 1664525 + 1013904223) % (2**32), min_val, max_val)
|
||||
t1 = time.perf_counter()
|
||||
ext_time1 = t1 - t0
|
||||
|
||||
print('max_subarray_sum equality:', py_res1 == ext_res1)
|
||||
print('Python time:', py_time1)
|
||||
print('C ext time:', ext_time1)
|
||||
|
||||
# Total over 20 seeds
|
||||
t0 = time.perf_counter()
|
||||
py_res2 = total_max_subarray_sum_py(n, initial_seed, min_val, max_val)
|
||||
t1 = time.perf_counter()
|
||||
py_time2 = t1 - t0
|
||||
|
||||
t0 = time.perf_counter()
|
||||
ext_res2 = ext.total_max_subarray_sum(n, initial_seed, min_val, max_val)
|
||||
t1 = time.perf_counter()
|
||||
ext_time2 = t1 - t0
|
||||
|
||||
print('total_max_subarray_sum equality:', py_res2 == ext_res2)
|
||||
print('Python total time:', py_time2)
|
||||
print('C ext total time:', ext_time2)
|
||||
@@ -0,0 +1,16 @@
|
||||
|
||||
import time
|
||||
import zz_my_module
|
||||
|
||||
def python_hello_world():
|
||||
print("Hello, World!")
|
||||
|
||||
start = time.time()
|
||||
python_hello_world()
|
||||
end = time.time()
|
||||
print(f"Python function execution time: {end - start:.6f} seconds")
|
||||
|
||||
start = time.time()
|
||||
zz_my_module.hello_world()
|
||||
end = time.time()
|
||||
print(f"C extension execution time: {end - start:.6f} seconds")
|
||||
@@ -0,0 +1,28 @@
|
||||
|
||||
#include <Python.h>
|
||||
|
||||
// Function to be called from Python
|
||||
static PyObject* zz_hello_world(PyObject* self, PyObject* args) {
|
||||
printf("Hello, World!\n");
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
// Method definition structure
|
||||
static PyMethodDef zz_my_methods[] = {
|
||||
{"hello_world", zz_hello_world, METH_VARARGS, "Print 'Hello, World!'"},
|
||||
{NULL, NULL, 0, NULL} // Sentinel
|
||||
};
|
||||
|
||||
// Module definition
|
||||
static struct PyModuleDef zz_my_module = {
|
||||
PyModuleDef_HEAD_INIT,
|
||||
"zz_my_module",
|
||||
"Extension module that prints Hello, World!",
|
||||
-1,
|
||||
zz_my_methods
|
||||
};
|
||||
|
||||
// Module initialization function
|
||||
PyMODINIT_FUNC PyInit_zz_my_module(void) {
|
||||
return PyModule_Create(&zz_my_module);
|
||||
}
|
||||
Reference in New Issue
Block a user