[Tutor] totalViruses[i] /= float(numTrials),

Oscar Benjamin oscar.j.benjamin at gmail.com
Thu Apr 25 00:58:52 CEST 2013


On 24 April 2013 23:41, Alan Gauld <alan.gauld at btinternet.com> wrote:
> On 24/04/13 20:32, Oscar Benjamin wrote:
>>
>> On 24 April 2013 20:07, Alan Gauld <alan.gauld at btinternet.com> wrote:
>>>
>>> On 24/04/13 16:52, Dave Angel wrote:
>>>
>>>>> Does it mean? ;  totalViruses[i] = totalViruses[i]/float(numTrials)
>>>>>
>>>> As the others have said, that's exactly right, at least if
>>>> totalViruses[i] is immutable, like an int or a float.
>>>
>>> What difference does immutability make here?
>
>> The subtle distinction that Dave is referring to is about modifying an
>> object in place vs rebinding a name to a newly created object.
>
> Sure, the bejhaviour with regard to the objects after the opreation is
> slightly different. But it makes noi dsifference to the duality of
>
> x += n
> v
> x = x + n
>
> The mutability issues are identical.

Mutability of Python objects is a convention rather than any hard
property of the object itself. One part of that convention is whether
or not __iadd__ returns a new object or mutates in place.

>
>> Which behaviour occurs is entirely up to the author of the __iadd__
>> method of the class in question. This method can modify and return
>> self or it can return a different object.
>
> This does make a difference because iadd (etc) can make a difference and I
> had forgotten that there are a separate set of operator methods for the ixxx
> operations, I was assuming that ixxx called the standard xxx.

It does if __ixxx__ is not defined:

>>> class A(object):
...   def __add__(left, right):
...     print('Add called')
...     return 'whatever'
...
>>> a = A()
>>> a + 1
Add called
'whatever'
>>> b = a+1
Add called
>>> b
'whatever'
>>> a += 1  # Calls __add__
Add called
>>> a
'whatever'
>>> class B(object):
...   def __add__(left, right):
...     print('Add called')
...     return 'whatever'
...   def __iadd__(self, right):
...     print('iAdd called')
...     return 'something else'
...
>>> b = B()
>>> b + 1
Add called
'whatever'
>>> b += 1
iAdd called
>>> b
'something else'

> So in the
> special case of a user type implementing xxx differently to ixxx the
> behaviour might differ. But for all other cases I can think of the duality
> will still work? Apart from this exception
>
> x += y
>
> will yield the same result as
>
> x = x + y
>
> I think....

By convention mutable types always implement __ixxx__ differently from
__xxx__. For lists __iadd__ is the same as extend and mutates the
existing list. For numpy arrays __ixxx__ modifies elements in place so
that array+=val will add val to all elements of array in-place, rather
then creating a new array. This always makes a difference if there are
other references to the object (as in the example I gave).

And here's another example:
>>> c = ([],)
>>> c
([],)
>>> c[0] = c[0] + [1]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
>>> c
([],)
>>> c[0] += [1]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
>>> c
([1],)


Oscar


More information about the Tutor mailing list