【问题标题】:Pythonic way to copy list to a sip.voidptr from QSharedMemory将列表从 QSharedMemory 复制到 sip.voidptr 的 Pythonic 方式
【发布时间】:2018-07-04 08:55:25
【问题描述】:

我正在使用 PyQT5 和 QSharedMemory 类。我正在创建一个可以容纳 6 个 1 字节元素的共享内存。要将这些元素复制到共享内存数组中,我将循环遍历 python 列表中的元素,如下面的 sn-p:

f = shared_mem.data()
k = f.asarray()
memtocopy = [0,1,2,3,4,5]
for i in range(0,len(memtocopy)):
    k[i]  = memtocopy[i]
shared_mem.unlock()

这似乎非常不合 Python 和样板代码。我想知道是否有更合适的方法来达到相同的结果?

使用时

k[:] = memtocopy

或:

k[:] = np.asarray(memtocopy,np.uint8)

它将失败并显示错误消息:

TypeError: can only assign another array of unsigned char to the slice

复制的整个测试代码如下所示:

from PyQt5 import QtCore 

# Create shared memory and attach it
shared_mem = QtCore.QSharedMemory()
shared_mem.setNativeKey("test")
shared_mem.create(4*6)
shared_mem.attach()


# Fill in 
shared_mem.lock()
f = shared_mem.data()
k = f.asarray()

memtocopy = [0,1,2,3,4,5]

# Loop in question
for i in range(0,len(memtocopy)):
    k[i]  = memtocopy[i]

shared_mem.unlock()



# Read out
shared_mem.lock()
f1 = shared_mem.data()
k1 = f1.asarray()
shared_mem.unlock()

# Test results
if k1[0] == memtocopy[0]:
    print("success!")
else:
    print("fail!")

【问题讨论】:

  • 为什么不k[:] = memtocopy
  • 这将导致 TypeError: can only assign another array of unsigned char to the slice,我也编辑了问题以显示这种情况
  • 那么这可能是弄清楚它想要什么数组类型的问题。我猜ctypes,但也许它支持缓冲协议。 PyQt's documentation 没有帮助。
  • sip.voidptr.asarray 是 4.16.5 版的新功能,这解释了为什么我在 Debian Jessie 中没有它。所以数组类型是sip.array,它也恰好只在现有的情况下被记录。
  • sip should support the buffer protocol,所以使用 Python array.arraybytearray 应该真的可以工作。整数列表不会。

标签: python pyqt pyqt5 qsharedmemory


【解决方案1】:

这是一种使用 structmemoryview 的更简单的方法,它使用一对单行代码读取和写入数据 :

import struct
from PyQt5 import QtCore

shared_mem = QtCore.QSharedMemory()
shared_mem.setNativeKey("test")
shared_mem.create(4*6)
shared_mem.attach()

memtocopy = [0,1,2,3,4,5]

try:

    # Fill in 
    shared_mem.lock()
    shared_mem.data()[:] = memoryview(struct.pack('=6i', *memtocopy))
    shared_mem.unlock()

    # Read out
    shared_mem.lock()
    # python3
    k = memoryview(shared_mem.data()).cast('i')
    # python2
    # k = struct.unpack('=6i', memoryview(shared_mem.data()))
    shared_mem.unlock()

    if k[3] == memtocopy[3]:
        print("success!")
    else:
        print("fail!")

finally:

    shared_mem.detach()

【讨论】:

  • 我假设 '=6i' 用于复制 6 个整数?
  • @Kev1n91。是的 - 格式已解释 here= 应该确保 memoryview cast 在所有平台上都以相同的方式工作。当然,如果你只针对一个平台,你可以使用6i
  • 我收到错误“memorieveiw”对象没有属性转换
  • @Kev1n91。那是因为您已更改为 python2。显然我的答案使用了 python3,因为这是你原来的问题使用的。无论如何,我已经在我的答案中添加了一个 python2 单线。
  • 我没有注意到,我在一个不由我处理的 docker 容器上。很抱歉搞砸了
【解决方案2】:

经过一番折腾,我设法产生了一种对我有用的组合:

a = array.array('i', range(6))
f[:] = buffer(a)
b = array.array('i')
b.fromstring(buffer(f))

这依赖于缓冲区协议来双向读取。您可能可以直接将数组与k 一起使用,并且fromstring 在以后的版本中已重命名为frombytes

在 Python 3.4 中,这有效:

a = array.array('i', range(6))
f[:] = memoryview(a).cast('B')
b = array.array('i')
b.frombytes(memoryview(f))

memoryview 替换了 buffer,但知道元素有 4 个字节大,因此需要额外的强制转换。

【讨论】:

  • 这在 python3 中不起作用(OP 似乎正在使用它),因为没有 buffer 函数(你不能简单地用 memoryview 替换它)。
  • 我几乎可以 - 需要一个演员表。
  • 如果使用 integersr 会发生什么?此时 frombytes 将无法使用?
  • 这确实使用整数('i' 输入数组)。 frombytes 只是告诉它从内存中加载。
猜你喜欢
  • 2019-12-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-26
  • 2013-09-10
  • 1970-01-01
  • 2021-11-22
  • 1970-01-01
相关资源
最近更新 更多