您当前的位置: 首页 >  Python
  • 0浏览

    0关注

    483博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

Python与C语言混合编程:通过通过ctypes.cdll加载python扩展组件

高精度计算机视觉 发布时间:2019-01-27 14:49:28 ,浏览量:0

通过ctypes扩展python组件可能是最简单的python扩展了。

源码

sample.h和sample.c的源码这里不重复了,需要的请参考:https://blog.csdn.net/tanmx219/article/details/86665706 目录结构是这样的 dev |__sample.h |__sample.c |__Makefile |__sub01              |__sample.py              |__libsample.so

Makefile

osx:
	gcc -shared -undefined dynamic_lookup sample.c -o libsample.so

linux:
	gcc -g -Wall -shared -fPIC sample.c -o libsample.so

因为我使用的是Ubuntu18.04,所以直接在dev目录下输入命令 $ make linux 即可得到libsample.so,如果要在sub01目录下使用,则需要把该文件拷贝到sub01目录下去。

sample.py

# sample.py
import ctypes
import os
from ctypes import util, cdll
# .so file is located in the directory above. See Makefile for
# build instructions
#_path = '../libsample.so'
test_path = util.find_library('/home/matthew/dev/libsample.so')

prev_path = ctypes.util.find_library('../libsample.so')
dir_path = os.path.dirname(os.path.realpath(__file__)) + '/libsample.so'

_mod = ctypes.cdll.LoadLibrary(dir_path)

# int gcd(int, int)
gcd = _mod.gcd
gcd.argtypes = (ctypes.c_int, ctypes.c_int)
gcd.restype = ctypes.c_int

# int in_mandel(double, double, int)
in_mandel = _mod.in_mandel
in_mandel.argtypes = (ctypes.c_double, ctypes.c_double, ctypes.c_int)
in_mandel.restype = ctypes.c_int

# int divide(int, int, int *)
_divide = _mod.divide
_divide.argtypes = (ctypes.c_int, ctypes.c_int, ctypes.POINTER(ctypes.c_int))
_divide.restype = ctypes.c_int

def divide(x, y):
    rem = ctypes.c_int()
    quot = _divide(x,y,rem)
    return quot,rem.value

# void avg(double *, int n)

# Define a special type for the 'double *' argument
class DoubleArrayType:
    def from_param(self, param):
        typename = type(param).__name__
        if hasattr(self, 'from_'+typename):
            return getattr(self, 'from_'+typename)(param)
        elif isinstance(param, ctypes.Array):
            return param
        else:
            raise TypeError("Can't convert %s" % typename)

    # Cast from array.array objects
    def from_array(self, param):
        if param.typecode != 'd':
            raise TypeError('must be an array of doubles')
        ptr, _ = param.buffer_info()
        return ctypes.cast(ptr, ctypes.POINTER(ctypes.c_double))

    # Cast from lists/tuples
    def from_list(self, param):
        val = ((ctypes.c_double)*len(param))(*param)
        return val

    from_tuple = from_list

    # Cast from a numpy array
    def from_ndarray(self, param):
        return param.ctypes.data_as(ctypes.POINTER(ctypes.c_double))
        
DoubleArray = DoubleArrayType()
_avg = _mod.avg
_avg.argtypes = (DoubleArray, ctypes.c_int)
_avg.restype = ctypes.c_double

def avg(values):
    return _avg(values, len(values))

# struct Point { }
class Point(ctypes.Structure):
    _fields_ = [('x', ctypes.c_double),
                ('y', ctypes.c_double)]

# double distance(Point *, Point *)
distance = _mod.distance
distance.argtypes = (ctypes.POINTER(Point), ctypes.POINTER(Point))
distance.restype = ctypes.c_double
如何使用

在sub01目录下,就可以这样使用了,

$ python
>>>import sample
>>>print(sample.gcd(35,42))

下面相同,都是测试代码,请自行验证
print( sample.in_mandel(0,0,500))
print( sample.in_mandel(2.0,1.0,500))
print( sample.divide(42,8) )
print( sample.avg([1,2,3]) )
p1 = sample.Point(1,2) 
p2 = sample.Point(4,5) 
print(p1 )
print(p2 )
print( sample.distance(p1,p2) )
说明

这里要注意,在sample.py中,通过ctypes.cdll加载组件时,我使用了三个路径,如果你的libsample.so在dev目录下,则应该使用prev_path;如果你和我一样,把libsample.so拷贝到了sub01目录下面,那么就可以使用dir_path, _mod = ctypes.cdll.LoadLibrary(dir_path)

函数的数据类型必须说明,例如

gcd = _mod.gcd                                            #表示最大公约数函数gcd gcd.argtypes = (ctypes.c_int, ctypes.c_int)   #gcd 输入函数的数据类型 gcd.restype = ctypes.c_int                            #gcd 输出函数的数据类型

 

关注
打赏
1661664439
查看更多评论
立即登录/注册

微信扫码登录

0.0377s