添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

I am using PyQT5 and the QSharedMemory class. I am creating a shared memory which can hold up 6 1-byte elements. To copy these elments in the shared memory array I am looping over the elments from the python list like the following snippet:

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()

Which seems very unpythonic and boilerplate-code like. I am wondering if there is a more suitable way of achieving the same result?

When using

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

It will fail with the error message:

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

The whole test code for reproducing looks like the following:

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!")
                This will result in TypeError: can only assign another array of unsigned char to the slice, I have edited the question to show this case, too
– Kev1n91
                Jul 4, 2018 at 9:06
                Then it might be a matter of figuring out what array type it wants. I'd guess ctypes, but perhaps it supports the buffer protocol. PyQt's documentation was no help.
– Yann Vernier
                Jul 4, 2018 at 9:09
                sip.voidptr.asarray is new from version 4.16.5, which explains why I didn't have it in Debian Jessie. So the array type is sip.array, which again happens to be documented only as far as existing.
– Yann Vernier
                Jul 4, 2018 at 9:20
                sip should support the buffer protocol, so using a Python array.array or bytearray should really work. Lists of ints won't.
– Yann Vernier
                Jul 4, 2018 at 9:25

Here's a simpler approach using struct and memoryview that reads and writes the data with a couple of one-liners

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]
    # 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()
                @Kev1n91. Yes - the format is explained here. The = should ensure the memoryview cast works the same way on all platforms. Of course, if you're only targeting one platform, you can just use 6i.
– ekhumoro
                Jul 5, 2018 at 10:53
                @Kev1n91. That's because you've changed to python2. Obviously my answer uses python3, because that is what your original question uses. Anyway, I've added a python2 one-liner to my answer.
– ekhumoro
                Jul 12, 2018 at 0:10
                I haven't noticed that, I am on a docker container which is not handled by me. Sorry about that mess up
– Kev1n91
                Jul 12, 2018 at 8:07

After a bit of fiddling about, I managed to produce one combination that functioned for me:

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

This relies on the buffer protocol for reading both ways. It is likely you can use the array directly with your k, and fromstring has been renamed to frombytes in later versions.

In Python 3.4, this worked:

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

memoryview replaced buffer, but knew the elements were 4 bytes large, so it required an additional cast.

This won't work in python3 (which the OP seems to be using), because there is no buffer function (and you cannot simply replace it with memoryview). – ekhumoro Jul 4, 2018 at 11:36 This does use integers ('i' type in array). frombytes simply tells it to load from memory. – Yann Vernier Jul 4, 2018 at 14:10

Thanks for contributing an answer to Stack Overflow!

  • Please be sure to answer the question. Provide details and share your research!

But avoid

  • Asking for help, clarification, or responding to other answers.
  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.