python - 将 Python 2 代码移植到 Python 3 时处理 ctypes 和 ASCII 字符串

标签 python python-3.x ctypes porting visa

我昨晚受够了,开始将 PyVISA 移植到 Python 3 (此处的进度:https://github.com/thevorpalblade/pyvisa)。

只要我将设备地址(好吧,实际上是任何字符串)作为 ASCII 传递,我已经达到了一切正常的地步。字符串而不是默认的 unicode 字符串(例如,
HP = vida.instrument(b"GPIB::16") 有效,而 HP = vida.instrument("GPIB::16") 不会,引发 ValueError。

理想情况下,最终用户不必关心字符串编码。 关于我应该如何处理这个问题有什么建议吗?可能在 ctypes 类型定义中?

就目前而言,相关的 ctypes 类型定义是:

ViString = _ctypes.c_char_p

最佳答案

ctypes 与 Python 3 中的大多数内容一样,有意不在 unicode 和字节之间自动转换。这是因为在大多数用例中,这只会要求人们切换到 Python 3 来避免的相同类型的 mojibake 或 UnicodeEncodeError 灾难。

但是,当您知道自己只处理纯 ASCII 时,那就是另一回事了。你必须是明确的——但你可以将这种明确性分解到包装器中。


Specifying the required argument types (function prototypes) 中所述,除了标准的 ctypes 类型之外,您还可以传递任何具有 from_param 类方法的类——它通常返回某种类型(通常是同一类型)的实例_as_parameter_ 属性,但也可以只返回原生 ctypes 类型的值。

class Asciifier(object):
    @classmethod
    def from_param(cls, value):
        if isinstance(value, bytes):
            return value
        else:
            return value.encode('ascii')

这可能不是您想要的确切规则——例如,它会在 bytearray 上失败(就像 c_char_p 一样),即使它可以悄悄地转换为bytes…但是你不想隐式地将 int 转换为 bytes。无论您决定什么规则,都应该易于编码。


这是一个示例(在 OS X 上;您显然必须更改 libc 为 linux、Windows 等加载的方式,但您大概知道该怎么做):

>>> libc = CDLL('libSystem.dylib')
>>> libc.atoi.argtypes = [Asciifier]
>>> libc.atoi.restype = c_int
>>> libc.atoi(b'123')
123
>>> libc.atoi('123')
123
>>> libc.atoi('123') # Unicode fullwidth digits
ArgumentError: argument 1: <class 'UnicodeEncodeError'>: 'ascii' codec can't encode character '\uff10' in position 0: ordinal not in range(128)
>>> libc.atoi(123)
ArgumentError: argument 1: <class 'AttributeError'>: 'int' object has no attribute 'encode'

显然,如果这些异常对于您的用例来说不够清晰,您可以捕获异常并引发另一个异常。

您可以类似地编写一个 Utf8ifier 或一个 Encodifier(encoding, errors=None) 类工厂,或者您需要的任何其他特定库并将其粘贴到argtypes 以同样的方式。


如果您还想自动解码返回类型,请参阅 Return typeserrcheck .


最后一件事:当您确定数据应该是 UTF-8,但您想处理它们与 Python 2.x 不同的情况会(通过按原样保留它们),您甚至可以在 3.x 中这样做。使用前面提到的 Utf8ifier 作为您的 argtype,解码器 errcheck,并使用 errors=surrogateescape .参见 here一个完整的例子。

关于python - 将 Python 2 代码移植到 Python 3 时处理 ctypes 和 ASCII 字符串,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21295945/

相关文章:

python - 确定进程是否可以移动/删除文件的可移植方法?

带日期的python datetime实例检查返回true

python - 如何用Python模拟键盘点击来控制游戏?

python - 具有多处理的共享内存字符串数组

python-3.x - GridSearchCV - XGBoost - 提前停止

python - 如何在 python 中使用 ctypes 获取 Windows 窗口名称

python - 当某些条目需要从不同位置拆分时,如何按连续空格拆分

python - 如何在 django rest 框架中反转 ViewSet 自定义操作的 URL

python - 读入 pandas 列作为 base64 字符串

Python3 中的 Python 命名空间包