Python ctypes:获取变量类型和值问题

2024-06-16 10:10:35 发布

您现在位置:Python中文网/ 问答频道 /正文

我想通过使用ctypes在一些Python代码中使用C库。 我的问题是我不懂C语言。我试着读代码和C结构已经好几天了,但我还是被一个问题困住了。我对Python也相当陌生,因为我目前正在从Matlab进行转换,因此我的Python仅限于科学的Python应用程序。这个问题非常具体,但我认为解决方案是一般C库/Python链接感兴趣的。在

我用的是一个叫做Iphreeqc的地球化学模型`http://wwwbrr.cr.usgs.gov/projects/GWC_coupled/phreeqc/index.html(iphreeqc-2.18.0-5314。焦油gz,从OS X 10.6上的源代码编译。超链接不工作,因为SO垃圾邮件预防)。我想从C库的计算中提取值到Python中。在

我怀疑我在Python代码的结构和联合部分中出错了,但我似乎无法找出原因。在

Python代码:

import ctypes

iphreeqc = ctypes.CDLL("libiphreeqc.0.dylib", ctypes.RTLD_GLOBAL)

# C structures from var.h 
class VAR_TYPE(ctypes.Structure):
    _fields_ = [
        ("TT_EMPTY",ctypes.c_int),
        ("TT_ERROR",ctypes.c_int),
        ("TT_LONG",ctypes.c_int),
        ("TT_DOUBLE",ctypes.c_int),
        ("TT_STRING",ctypes.c_int)]


(TT_EMPTY,
TT_ERROR,
TT_LONG,
TT_DOUBLE,
TT_STRING)=map(ctypes.c_int, xrange(5))


class VRESULT(ctypes.Structure):
    _fields_ = [
        ("VR_OK",ctypes.c_int),
        ("VR_OUTOFMEMORY",ctypes.c_int),
        ("VR_BADVARTYPE",ctypes.c_int),
        ("VR_INVALIDARG",ctypes.c_int),
        ("VR_INVALIDROW",ctypes.c_int),
        ("VR_INVALIDCOL",ctypes.c_int)]

(VR_OK,
 VR_OUTOFMEMORY,
 VR_BADVARTYPE,
 VR_INVALIDARG,
 VR_INVALIDROW,
 VR_INVALIDCOL)=map(ctypes.c_int, xrange(0,-6,-1))

class _U(ctypes.Union):
    _fields_ = [("lVal", ctypes.c_long),
                ("dVal", ctypes.c_double),
                ("sVal", ctypes.c_char),
                ("vresult", VRESULT)]

class VAR(ctypes.Structure):
   _anonymous_ = ("pvar",)
   _fields_ = [
        ("pvar", _U),
        ("type", VAR_TYPE)]

# Run model        
Id=iphreeqc.CreateIPhreeqc()
dbloade = iphreeqc.LoadDatabase(Id,"phreeqc.dat")
estring=iphreeqc.OutputErrorString(Id)

# Model input
iphreeqc.AccumulateLine(Id,"TITLE Example 2.--Temperature dependence of solubility")
iphreeqc.AccumulateLine(Id,"                  of gypsum and anhydrite             ")
iphreeqc.AccumulateLine(Id,"SOLUTION 1 Pure water                                 ")
iphreeqc.AccumulateLine(Id,"        pH      7.0                                   ")
iphreeqc.AccumulateLine(Id,"        temp    25.0                                  ")
iphreeqc.AccumulateLine(Id,"EQUILIBRIUM_PHASES 1                                  ")
iphreeqc.AccumulateLine(Id,"        Gypsum          0.0     1.0                   ")
iphreeqc.AccumulateLine(Id,"        Anhydrite       0.0     1.0                   ")
iphreeqc.AccumulateLine(Id,"REACTION_TEMPERATURE 1                                ")
iphreeqc.AccumulateLine(Id,"        25.0 75.0 in 50 steps                         ")
iphreeqc.AccumulateLine(Id,"SELECTED_OUTPUT                                       ")
iphreeqc.AccumulateLine(Id,"        -file   ex2.sel                               ")
iphreeqc.AccumulateLine(Id,"        -user_punch true                                  ")
iphreeqc.AccumulateLine(Id,"        -reset false                                  ")
iphreeqc.AccumulateLine(Id,"        -simulation false                                  ")
iphreeqc.AccumulateLine(Id,"        -selected_out true                                  ")
iphreeqc.AccumulateLine(Id,"        USER_PUNCH                                      ")
iphreeqc.AccumulateLine(Id,"        -start                                           ")
iphreeqc.AccumulateLine(Id,"        10 punch - LA('H+')                                  ")
iphreeqc.AccumulateLine(Id,"        -end                                            ")
iphreeqc.AccumulateLine(Id,"END                                                       ")

# run model
runout=iphreeqc.RunAccumulated(Id)
estring2=iphreeqc.OutputErrorString(Id)

a=iphreeqc.GetSelectedOutputRowCount(Id)
b=iphreeqc.GetSelectedOutputColumnCount(Id)
print a
print b # this works, gives correct number of rows and columns  

vart=VAR() 
iphreeqc.VarInit(ctypes.byref(vart)) 

c=iphreeqc.GetSelectedOutputValue(Id, 43, 0, ctypes.byref(vart)) #tries to extract value from row 43, column 1

print c # c is here VRESULT. this works properly giving the right error number (0 to -6). Gives 0 in this case which is VR_OK

所选行、列中的值是double,但我也尝试过使用字符串值和long(整型)值,但没有成功。 我希望如此变量dVal(对于string或long,则为.sVal或lVal)以包含我想要的值,但它不是。 我也希望VAR_TYPE的TT_u字段中有一个是1,但它们都是0。 似乎.dVal、.sVal和.lVal实际上包含VAR_类型号(介于0和4之间),并且正确地报告了这一点(即3表示double类型,2表示long类型)。在

我的问题是:如何修复代码,使VAR_TYPE字段反映变量类型,而变量类型现在在.lVal字段中返回。 我怎样才能得到我想提取的正确值变量x值领域?在Python结构/联合代码中是否缺少一些指针?

结构和联合来自的C源(Var.h):

http://wwwbrr.cr.usgs.gov/projects/GWC_coupled/iphreeqc/Var_8h_source.html

我试图在Python中重现的C示例(v是Python代码中的变量'vart',我暂时忽略循环等):

^{pr2}$

C示例取自:(向下滚动一点) http://wwwbrr.cr.usgs.gov/projects/GWC_coupled/iphreeqc/IPhreeqc_8h.html#a9f0ffd11e25a7e8f05d800623b14acf5

我在OSX10.6.6上使用的是cTypes1.1.0和Python2.6.6

很抱歉这个问题太长了,希望一些聪明人能帮我解决问题,或者给我指出正确的方向。在

非常感谢


Tags: 代码id类型fieldsvartypectypes结构
2条回答

一个问题是枚举不是结构。还要确保结构中的字段的顺序与C头的顺序相同(“type”排在第一位)。试试这个:

import ctypes

VAR_TYPE = ctypes.c_int
TT_EMPTY  = 0
TT_ERROR  = 1
TT_LONG   = 2
TT_DOUBLE = 3
TT_STRING = 4

VRESULT = ctypes.c_int
VR_OK          =  0
VR_OUTOFMEMORY = -1
VR_BADVARTYPE  = -2
VR_INVALIDARG  = -3
VR_INVALIDROW  = -4
VR_INVALIDCOL  = -5

class _U(ctypes.Union):
    _fields_ = [
        ('lVal',ctypes.c_long),
        ('dVal',ctypes.c_double),
        ('sVal',ctypes.c_char_p),
        ('vresult',VRESULT)]

class VAR(ctypes.Structure):
    _anonymous_ = ('u',)
    _fields_ = [
        ('type',VAR_TYPE),
        ('u',_U)]

有一些短语(http://www.phreeqpy.com)可以解决您的问题。 免责声明:我是作者。在

PhreeqPy是IPhreeqc COM/DLL/共享库的包装器。 您应该通过Linux上的共享库或 Mac操作系统。在

以下是处理联合和结构的部分代码:

class VARUNION(ctypes.Union):
    # pylint: disable-msg=R0903
    # no methods
    """Union with types.

    See Var.h in PHREEQC source.
    """
    c_int = ctypes.c_int
    _fields_ = [('long_value', ctypes.c_long),
                ('double_value', ctypes.c_double),
                ('string_value', ctypes.c_char_p),
                ('error_code', c_int)]

class VAR(ctypes.Structure):
    # pylint: disable-msg=R0903
    # no methods
    """Struct with data type and data values.

    See Var.h in PHREEQC source.
    """
    c_int = ctypes.c_int
    _fields_ = [('type', c_int),
                ('value', VARUNION)] 

相关问题 更多 >