1

I recently found out how to use tuples thanks to great contributions from SO users(see here). However I encounter the problem that I can't add a tuple to another tuple stored inside an array of tuples. For instance if I define:

arrtup=empty((2,2),dtype=('int,int'))
arrtup[0,1]=(3,4)

Then if I try to add another tuple to the existing tupe to come up with a multidimensional index:

arrtup[0,1]+(4,4)

I obtain this error:

TypeError: unsupported operand type(s) for +: 'numpy.void' and 'tuple'

Instead of the expected (3,4,4,4) tuple, which I can obtain by:

(3,4)+(4,4)

Any ideas? Thanks!

2 Answers 2

4

You are mixing different concepts, I'm afraid.

Your arrtup array is not an array of tuples, it's a structured ndarray, that is, an array of elements that look like tuples but in fact are records (numpy.void objects, to be exact). In your case, you defined these records to consist in 2 integers. Internally, NumPy creates your array as a 2x2 array of blocks, each block taking a given space defined by your dtype: here, a block consists of 2 consecutive blocks of size int (that is, each sub-block takes the space an int takes on your machine).

When you retrieve an element with arrtup[0,1], you get the corresponding block. Because this block is structured as two-subblocks, NumPy returns a numpy.void (the generic object representing structured blocks), which has the same dtype as your array.

Because you set the size of those blocks at the creation of the array, you're no longer able to modify it. That means that you cannot transform your 2-int records into 4-int ones as you want.

However, you can transform you structured array into an array of objects:

new_arr = arrtup.astype(object)

Lo and behold, your elements are no longer np.void but tuples, that you can modify as you want:

new_arr[0,1] = (3,4) # That's a tuple
new_arr[0,1] += (4,4) # Adding another tuple to the element

Your new_arr is a different beast from your arrtup: it has the same size, true, but it's no longer a structured array, it's an array of objects, as illustrated by

>>> new_arr.dtype
dtype("object")

In practice, the memory layout is quite different between arrtup and newarr. newarr doesn't have the same constraints as arrtup, as the individual elements can have different sizes, but object arrays are not as efficient as structured arrays.

Sign up to request clarification or add additional context in comments.

5 Comments

That is a very nice explanation, thanks! So in practical termns, the ndarray is always filled with numpy.void objects, regardless of what the dtype says. In that case, the dtype is only a useful definition in terms of storing data, since I am able to store a tupe of the kind if defined, but not able to retrieve it. Right? I still dont understand what's the point in not being able to just yield the object out of the array in the shape I defined it with .
That's cool! Thank you, so instead of the initial empty statement I will extend it to arrtup=empty((2,2),dtype=('int,int')).astype(object) or a shorter less specific version of arrtup=empty((2,2),dtype=object). Thank you!
@vint-i-vuit: Yep, using object for your dtype will let you do what you want. Compare np.empty((2,2), dtype=(int,int)) and np.empty((2,2),dtype=object)
@Pierre GM: actually np.empty((2,2), dtype=(int,int)) defines an array in each ndarray position, not a tuple, right? You need the single quotes like: dtype=('int,int'). But I agree with your point :)
@vint-i-vuit I meant dtype=[('',int),('',int)],sorry.
2

The traceback is pretty clear here. arrtup[0,1] is not a tuple. It's of type `numpy.void'.

You can convert it to a tuple quite easily however:

tuple(arrtup[0,1])

which can be concatenated with other tuples:

tuple(arrtup[0,1]) + (4,4)

4 Comments

To elaborate - numpy doesn't provide __add__ for its void type/object; and considering the name, it makes sense.
damnit, but why is it a void!? I fill it with a tuple, dont I?
@vint-i-vuit -- No -- you fill it with the integers that were stored in your tuple. when you do a[...] = ..., the __setitem__ method is called on a. In this case, __setitem__ takes the information from the tuple and stores it as a numpy.void type.
that works, thanks! but I still don't understand why I can't retrieve the tuple stored.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.