Dưới đây là một ví dụ nhỏ nhưng hoàn toàn đi qua mảng NumPy đến một chức năng C bên ngoài, một cách logic
fc(int N, double* a, double* b, double* z) # z = a + b
sử dụng Cython. (Điều này chắc chắn là nổi tiếng cho những ai biết nó cũng Comments đều được chào đón thay đổi cuối:... Ngày 23 tháng 2 năm 2011, cho Cython 0.14)
Đầu đọc hoặc đọc lướt Cython build và Cython with NumPy.
2 bước sau:
python f-setup.py build_ext --inplace
biến f.pyx
và fc.cpp
->f.so
, thư viện động
python test-f.py
import f
tải f.so
; f.fpy(...)
gọi C fc(...)
.
python f-setup.py
sử dụng distutils
để chạy cython, biên dịch và liên kết:
cython f.pyx -> f.cpp
biên dịch f.cpp
và fc.cpp
liên kết f.o fc.o
->f.so
, một động lib rằng python import f
sẽ được tải.
Đối với sinh viên, tôi khuyên bạn nên: lập sơ đồ các bước này, xem qua các tệp bên dưới, sau đó tải xuống và chạy chúng.
(distutils
là một gói phức tạp khổng lồ dùng để gói Python làm cho phân phối và cài đặt chúng. Ở đây chúng ta đang sử dụng chỉ là một phần nhỏ của nó để biên dịch và liên kết đến f.so
. Bước này không có gì để làm với Cython, nhưng nó có thể được khó hiểu;.. sai lầm đơn giản trong một .pyx có thể gây ra các trang thông báo lỗi khó hiểu từ g ++ biên dịch và liên kết Xem thêm distutils doc và/hoặc SO questions on distutils)
Giống như make
, setup.py
sẽ chạy lại cython f.pyx
và g++ -c ... f.cpp
nếu f.pyx
mới hơn f.cpp
.
Để dọn dẹp, rm -r build/
.
Một thay thế cho setup.py
sẽ chạy các bước riêng biệt, trong một kịch bản hay Makefile:
cython --cplus f.pyx -> f.cpp # see cython -h
g++ -c ... f.cpp -> f.o
g++ -c ... fc.cpp -> fc.o
cc-lib f.o fc.o -> dynamic library f.so
.
Sửa đổi các wrapper cc-lib-mac
dưới đây cho nền tảng và cài đặt của bạn: nó không đẹp, nhưng nhỏ.
Ví dụ thực sự về gói C Cython C, xem các tệp .pyx chỉ trong khoảng SciKit.
Xem thêm: Cython for NumPy users và SO questions/tagged/cython.
Để giải nén các tập tin sau đây, cắt dán rất nhiều vào một tập tin lớn, nói cython-numpy-c-demo
, sau đó trong Unix (trong một thư mục mới sạch) chạy sh cython-numpy-c-demo
.
#--------------------------------------------------------------------------------
cat >f.pyx <<\!
# f.pyx: numpy arrays -> extern from "fc.h"
# 3 steps:
# cython f.pyx -> f.c
# link: python f-setup.py build_ext --inplace -> f.so, a dynamic library
# py test-f.py: import f gets f.so, f.fpy below calls fc()
import numpy as np
cimport numpy as np
cdef extern from "fc.h":
int fc(int N, double* a, double* b, double* z) # z = a + b
def fpy(N,
np.ndarray[np.double_t,ndim=1] A,
np.ndarray[np.double_t,ndim=1] B,
np.ndarray[np.double_t,ndim=1] Z):
""" wrap np arrays to fc(a.data ...) """
assert N <= len(A) == len(B) == len(Z)
fcret = fc(N, <double*> A.data, <double*> B.data, <double*> Z.data)
# fcret = fc(N, A.data, B.data, Z.data) grr char*
return fcret
!
#--------------------------------------------------------------------------------
cat >fc.h <<\!
// fc.h: numpy arrays from cython , double*
int fc(int N, const double a[], const double b[], double z[]);
!
#--------------------------------------------------------------------------------
cat >fc.cpp <<\!
// fc.cpp: z = a + b, numpy arrays from cython
#include "fc.h"
#include <stdio.h>
int fc(int N, const double a[], const double b[], double z[])
{
printf("fc: N=%d a[0]=%f b[0]=%f \n", N, a[0], b[0]);
for(int j = 0; j < N; j ++){
z[j] = a[j] + b[j];
}
return N;
}
!
#--------------------------------------------------------------------------------
cat >f-setup.py <<\!
# python f-setup.py build_ext --inplace
# cython f.pyx -> f.cpp
# g++ -c f.cpp -> f.o
# g++ -c fc.cpp -> fc.o
# link f.o fc.o -> f.so
# distutils uses the Makefile distutils.sysconfig.get_makefile_filename()
# for compiling and linking: a sea of options.
# http://docs.python.org/distutils/introduction.html
# http://docs.python.org/distutils/apiref.html 20 pages ...
# https://stackoverflow.com/questions/tagged/distutils+python
import numpy
from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext
# from Cython.Build import cythonize
ext_modules = [Extension(
name="f",
sources=["f.pyx", "fc.cpp"],
# extra_objects=["fc.o"], # if you compile fc.cpp separately
include_dirs = [numpy.get_include()], # .../site-packages/numpy/core/include
language="c++",
# libraries=
# extra_compile_args = "...".split(),
# extra_link_args = "...".split()
)]
setup(
name = 'f',
cmdclass = {'build_ext': build_ext},
ext_modules = ext_modules,
# ext_modules = cythonize(ext_modules) ? not in 0.14.1
# version=
# description=
# author=
# author_email=
)
# test: import f
!
#--------------------------------------------------------------------------------
cat >test-f.py <<\!
#!/usr/bin/env python
# test-f.py
import numpy as np
import f # loads f.so from cc-lib: f.pyx -> f.c + fc.o -> f.so
N = 3
a = np.arange(N, dtype=np.float64)
b = np.arange(N, dtype=np.float64)
z = np.ones(N, dtype=np.float64) * np.NaN
fret = f.fpy(N, a, b, z)
print "fpy -> fc z:", z
!
#--------------------------------------------------------------------------------
cat >cc-lib-mac <<\!
#!/bin/sh
me=${0##*/}
case $1 in
"")
set -- f.cpp fc.cpp ;; # default: g++ these
-h* | --h*)
echo "
$me [g++ flags] xx.c yy.cpp zz.o ...
compiles .c .cpp .o files to a dynamic lib xx.so
"
exit 1
esac
# Logically this is simple, compile and link,
# but platform-dependent, layers upon layers, gloom, doom
base=${1%.c*}
base=${base%.o}
set -x
g++ -dynamic -arch ppc \
-bundle -undefined dynamic_lookup \
-fno-strict-aliasing -fPIC -fno-common -DNDEBUG `# -g` -fwrapv \
-isysroot /Developer/SDKs/MacOSX10.4u.sdk \
-I/Library/Frameworks/Python.framework/Versions/2.6/include/python2.6 \
-I${Pysite?}/numpy/core/include \
-O2 -Wall \
"[email protected]" \
-o $base.so
# undefs: nm -gpv $base.so | egrep '^ *U _+[^P]'
!
# 23 Feb 2011 13:38
Tôi chỉ vừa mới bọc C thư viện của tôi sử dụng Cython, bạn có thể muốn tham gia một hãy xem điều đó để biết ví dụ về cách thực hiện. Tôi đã giải thích toàn bộ quy trình chi tiết ở đây, bao gồm xây dựng và phân phối mô-đun: http://martinsosic.com/development/2016/02/08/wrapping-c-library-as-python-module.html. – Martinsos