[Numpy-discussion] Re: Histograms via indirect index arrays
robert.kern at gmail.com
Fri Mar 17 11:59:05 CST 2006
Piotr Luszczek wrote:
> On Friday 17 March 2006 13:29, Travis Oliphant wrote:
>>how does python interpret
>>g[idx] += 1
>>How does this get compiled to byte-code?
In : c = compile('g[idx] += 1', '<str>', 'single')
In : import dis
In : dis.dis(c)
1 0 LOAD_NAME 0 (g)
3 LOAD_NAME 1 (idx)
6 DUP_TOPX 2
10 LOAD_CONST 0 (1)
16 LOAD_CONST 1 (None)
>>There are two possibilities:
>>1) g[idx] creates a new object which then has 1 added to it using
>> This would not produce the desired behavior as g[idx] is a copy
>>of the data when idx is a
>> general indexing array as it is in this case. So, you make a
>>copy of those indices, add 1 to them
>> and then do what with the resut?
>>2) g[idx] += 1 gets converted to g[idx] = g[idx] + 1
>> This appears to be effectively what Python actually does. Notice
>>that there is no way for us to control this behavior because there is
>>no __inplace_with_indexing_add__ operator to over-ride.
>>There is no such single operation to over-ride for the object. In
>>other words, I don't see anyay for us to even alter the object to get
>>the behavior you want from that syntax. We can, of course, add a
>>function or method to do that, but I we would have to extend Python
>>to get the behavior you want here.
> Hardly. At least from what I'm seeing happens on a small example.
> 'g[idx] += 1' becomes ('g' and 'idx' are generic objects):
> __getitem__(self, idx)
> __setitem__(result of __iadd__)
> By design numpy returns views from __getitem__
Only for slices.
In : a = arange(10)
In : idx = [2,2,3]
In : a[idx]
Out: array([2, 2, 3])
In : b = a[idx]
In : b[-1] = 100
In : a
Out: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
> In this case, it would be view into 'self' and 'idx' so the __iadd__
> would just use the 'idx' directly rather than a copy.
> Finally, __setitem__ doesn't do anything since 'self' and 'value'
> will be the same.
No, value is the result of __iadd__ on the temporary array.
'g[idx] += 1' expands to:
tmp = g.__getitem__(idx)
val = tmp.__iadd__(1)
Given these class definitions:
def __getitem__(self, idx):
print 'A.__getitem__(%r)' % idx
def __setitem__(self, idx, value):
print 'A.__setitem__(%r, %r)' % (idx, value)
def __iadd__(self, x):
print 'B.__iadd__(%r)' % x
In : a = A()
In : a[[0, 2, 2, 1]] += 1
A.__getitem__([0, 2, 2, 1])
A.__setitem__([0, 2, 2, 1], B())
> Of course, this is just a quick draft. I don't know how it would work
> in practice and in other cases.
Aye, there's the rub.
robert.kern at gmail.com
"I have come to believe that the whole world is an enigma, a harmless enigma
that is made terrible by our own mad attempt to interpret it as though it had
an underlying truth."
-- Umberto Eco
More information about the Numpy-discussion