python 2和3之间的“map”函数问题

问题描述 投票:1回答:2

我正在使用其他人编写的代码来读取和编码来自数字/模拟转换器的数据。我尝试通过使用python 3来改进此代码,因为它是在python 2中编码的。

我已经减少了很多代码以理解为什么它在Python 3上不起作用并且发现了“map”函数行为的问题,因为它说“在Python 3中出现了错误,但在python 2中没有。

我不知道我在哪里做错了,因为我自己没有制作这个代码,有些部分我无法理解。我应该改变什么才能使它与python 3一起使用?


from DTOL import DTOL

io = DTOL(name='DT9818(00)')

io.Initialize('DT9818(00)')
io.setupGetSingleValue()

DTOL


import ctypes
from time import sleep
from DTOL_defs import *
from DTOL_prototypes import *

class DTOL:
    """ Data Translation DtOLWrapper Class """
    def __init__(self, name='DT9818(00)'):
        self.name = name
        self.data = []
        self.sshandle = []
        self.hdev = []
        self.range = (-10,10)
        self.rmin = ctypes.c_double(-10)
        self.rmax = ctypes.c_double(10)
        self.gain = ctypes.c_double(1)
        self.res = ctypes.c_uint(16)
        self.enc = ctypes.c_uint(OL_ENC_BINARY)
        self.val = 0

    def Initialize(self, name):
        print('Available Boards:')
        olDaEnumBoards(listboardscallback, 1)
        print('-----')
        print('Initializing: ' + str(name))
        name = name.encode('utf-8')
        hdev = olDaInitialize(name)
        self.hdev = hdev
        return hdev

    def GetSubsystem(self, subsystem_code, elemNum):
        print(subsystem_code)
        print(elemNum)
        sshandle = olDaGetDASS(self.hdev, subsystem_code, elemNum)
        self.sshandle = sshandle
        return sshandle

    def setupGetSingleValue(self):
        self.Initialize(self.name)
        self.GetSubsystem(OLSS_AD, ctypes.c_ulong(0))


if __name__ == "__main__":
    print("Usage: io=DTOL('DT9818(00)')")
    print("io.setupSingleValue()")
    print("io.getSingleValue()")
    io = DTOL()
    io.setupGetSingleValue()

DTOL_prototypes


import ctypes
from ctypes.util import find_library

dll = ctypes.CDLL(find_library('oldaapi64'))
dll2 = ctypes.CDLL(find_library('OLMEM64'))

def errcheck_all(ret, func, args):
    if ret:
        print("Error occured in"+ str(func))
        return

    return args

def errcheck_none(ret, func, args):
    if ret:
        print("Error occured in"+ str(func))
        print(ret)
        return

# ----------- Initialize ---------------------------------
prototype = ctypes.WINFUNCTYPE(ctypes.c_int, ctypes.c_char_p, ctypes.POINTER(ctypes.c_ulong))
paramflags = (1, "name"), (2,"hDev")
olDaInitialize = prototype(('olDaInitialize', dll), paramflags)
olDaInitialize.errcheck = errcheck_all
# -----------END Initialize ---------------------------------

# ----------- olDaGetDASS ---------------------------------
prototype = ctypes.WINFUNCTYPE(ctypes.c_int, ctypes.c_ulong, ctypes.c_long, ctypes.c_uint, ctypes.POINTER(ctypes.c_ulong))
paramflags = (1, "hDev"), (1,"SubsystemType"), (1,"uiElementNr"), (2,"adhandle")
olDaGetDASS = prototype(('olDaGetDASS',dll), paramflags)
olDaGetDASS.errcheck = errcheck_all
# ----------- olDaGetDASS ---------------------------------

DTOL_defs


import ctypes

(OLSS_AD, 
OLSS_DA, 
OLSS_DIN, 
OLSS_DOUT, 
OLSS_SRL, 
OLSS_CT) = list(map(ctypes.c_int, (range(6))))

OL_ENC_BINARY = 200

结果,我发现了python 3和2之间的区别:Python 3:

c_long(0)
<class 'ctypes.c_long'>
Available Boards:
Name = b'DT9818(00)'
Drivername = b'Dt9818'
1
-----
Initializing: DT9818(00)
Available Boards:
Name = b'DT9818(00)'
Drivername = b'Dt9818'
1
-----
Initializing: DT9818(00)
c_long(0)
c_ulong(0)
Error occured in<WinFunctionType object at 0x00000235269DC528>

Python 2:

c_long(0)
<class 'ctypes.c_long'>
Available Boards:
Name = DT9818(00)
Drivername = Dt9818
1
-----
Initializing: DT9818(00)
Available Boards:
Name = DT9818(00)
Drivername = Dt9818
1
-----
Initializing: DT9818(00)
c_long(0)
c_ulong(0L)

最后两个参数分别对应于“print(subsystem_code)”和“print(elemNum)”。

python-3.x dictionary ctypes converters
2个回答
1
投票

我不知道为什么你认为地图会成为问题。它的调用方式(从中构造一个列表)在两个Python版本上的工作方式相同。

张贴[Python 3]: ctypes - A foreign function library for Python

没有函数文档,我不能100%确定,但从它们声明的方式来看:

  1. olDaInitialize: prototype = ctypes.WINFUNCTYPE(ctypes.c_int, ctypes.c_char_p, ctypes.POINTER(ctypes.c_ulong)) paramflags = (1, "name"), (2, "hDev")
  2. olDaGetDASS: prototype = ctypes.WINFUNCTYPE(ctypes.c_int, ctypes.c_ulong, ctypes.c_long, ctypes.c_uint, ctypes.POINTER(ctypes.c_ulong)) paramflags = (1, "hDev"), (1, "SubsystemType"), (1, "uiElementNr"), (2, "adhandle")

我可以得出结论,返回值表示函数执行状态,通常:

  • 0表示成功
  • 表示错误代码的任何其他int值

但是,在Initialize中,你设置hDev(这是olDaInitialize的输出和olDaGetDASS的输入)(这里也存在类型不匹配,但它被自动转换隐藏):

hdev = olDaInitialize(name)
self.hdev = hdev

所以你给hdev分配olDaInitialize的状态是没有意义的。正确的方法是:

  • 在__init__中: self.hdev = ctypes.c_ulong(0)
  • 在初始化中: hdev = ctypes.c_ulong(0) status = olDaInitialize(name, ctypes.byref(hdev)) if status == 0: # Or whichever value means SUCCESS self.hdev = hdev

完全相同的事情也适用于adhandle(olDaGetDASS的最后一个参数),你在GetSubsystem中引用(作为sshandle)并且可能在代码中使用其他地方。

我们在改进部分:

  • 传递给__init__和Initialize的名称似乎是多余的。我建议把它留在初始化器中,并在体内做: self.name = name.encode("utf-8") 然后从Initialize中删除参数,并在其中使用self.name
  • 您正在使用errcheck功能,但现在它根本没有帮助。你可以改进它(例如通过显示错误代码)。关于[SO]: How to use ctypes' errcheck? (@CristiFati's answer)的更多细节
  • Initialize被调用两次:在主脚本和setupGetSingleValue中。你应该从一个地方删除电话(我会说后者)
  • 缺少olDaEnumBoards(和listboardscallback)。另外,第2行打印在哪里?
  • 尝试保持您的标识符名称一致([Python]: PEP 8 -- Style Guide for Python Code

@ EDIT0:

添加一些简化代码,以检查问题是否重现。

code.朋友:

#!/usr/bin/env python3

import sys
import ctypes


def main():
    oldaapi64 = ctypes.CDLL(find_library("oldaapi64"))
    olmem64 = ctypes.CDLL(find_library("olmem64"))

    oldainitialize = oldaapi64.olDaInitialize
    oldainitialize.argtypes = [
        ctypes.c_char_p, ctypes.POINTER(ctypes.c_ulong),
    ]
    oldainitialize.restype = ctypes.c_int

    oldagetdass = olmem64.olDaGetDASS
    oldagetdass.argtypes = [
        ctypes.c_ulong, ctypes.c_long, ctypes.c_uint, ctypes.POINTER(ctypes.c_ulong),
    ]
    oldagetdass.restype = ctypes.c_int

    dev = ctypes.c_ulong(0)
    res = oldainitialize(b"DT9818(00)", ctypes.byref(dev))
    print("{:s} returned {:d}. Dev: {:d}".format(oldainitialize.name, res, dev.value))

    OLSS_AD = 0
    element_num = 0
    handle = ctypes.c_ulong(0)
    res = oldagetdass(dev, OLSS_AD, element_num, ctypes.byref(handle))
    print("{:s} returned {:d}. Handle: {:d}".format(oldagetdass.name, res, handle.value))


if __name__ == "__main__":
    print("Python {:s} on {:s}\n".format(sys.version, sys.platform))
    main()
    print("Done.")

0
投票

我也尝试使用类似的ADC与python 3.x一起工作。我和你一样,来自使用python 2.7运行的pyDTOL模块。不幸的是,我遇到了同样的问题。我试图理解pyDTOL中真正发生的事情,并最终得到了与CristiFati类似的方法。我添加了释放ADC的功能。这是我的代码(适用于python 2.7,但有3.x的问题):

import ctypes
from ctypes.util import find_library

def main():
    ctypes.cdll.LoadLibrary(find_library('oldaapi64'))  
    oldaapi = ctypes.CDLL("oldaapi64") 

    name= b'DT9836S(00)'

    olDaInitialize = oldaapi.olDaInitialize
    olDaInitialize.argtypes = [ctypes.c_char_p, ctypes.POINTER(ctypes.c_ulong)]
    olDaInitialize.retype = ctypes.c_ulong

    hdev = ctypes.c_ulong()
    ret_init = olDaInitialize(name, ctypes.byref(hdev))
    print('hdev: ' + str(hdev))
    print('return from olDaInitialize: ' + str(ret_init))

    olDaGetDASS = oldaapi.olDaGetDASS
    olDaGetDASS.argtypes = [ctypes.c_ulong, ctypes.c_long, ctypes.c_uint, 
                            ctypes.POINTER(ctypes.c_ulong)]
    olDaGetDASS.restype = ctypes.c_ulong

    OLSS_AD = ctypes.c_long(0)
    sshandle = ctypes.c_ulong()
    ret_dass = olDaGetDASS(hdev.value, OLSS_AD, ctypes.c_uint(0), 
                           ctypes.byref(sshandle))
    print('sshandle: ' + str(sshandle))
    print('return from olDaGetDASS: ' + str(ret_dass))

    olDaReleaseDASS = oldaapi.olDaReleaseDASS
    olDaReleaseDASS.argtype = ctypes.c_ulong
    olDaReleaseDASS.restype = ctypes.c_ulong

    ret_rdass = olDaReleaseDASS(sshandle.value)

    olDaTerminate = oldaapi.olDaTerminate
    olDaTerminate.argtype = ctypes.c_ulong
    olDaTerminate.restype = ctypes.c_ulong

    ret_term = olDaTerminate(hdev.value)


if __name__ == "__main__":
    main()

Python 2.7中的输出:

hdev: c_ulong(11836704L)
return from olDaInitialize: 0
sshandle: c_ulong(11843088L)
return from olDaGetDASS: 0

Python 3.6中的输出:

hdev: c_ulong(3420637248)
return from olDaInitialize: 0
sshandle: c_ulong(0)
return from olDaGetDASS: 39

根据“oldaapi64 - manual”,返回值“0”表示“操作完成;没有错误。”olDaGetDass的后退值为39意味着:“指定了非法的设备句柄”。

在我看来,有两种可能性:hdev-pointer(来自“olDaInitialize”)在python 3中是不同的inperpreted,或者如果你将hdev传递给“olDaGetDASS”则会出现问题。

如果我们能找到解决方案,那就太好了!

编辑:来自CrisiFati的回复:DLL olmem64没有olDaGetDASS的功能

oldagetdass = olmem64.olDaGetDASS

你必须使用oldaapi64

oldagetdass = oldaapi64.olDaGetDASS

用户手册可在此处找到:

https://www.mccdaq.com/PDFs/Manuals/UMDataAcq.pdf附录A显示了一个例子。在调用约定中,声明返回值是unsigned long,并且使用Microsoft Pascal调用约定。

最好的问候

© www.soinside.com 2019 - 2024. All rights reserved.