In [ ]:

```
import numpy as np
```

In [ ]:

```
def id(x):
# This function returns the memory
# block address of an array.
return x.__array_interface__['data'][0]
```

In [ ]:

```
a = np.zeros(10); aid = id(a); aid
```

In [ ]:

```
b = a.copy(); id(b) == aid
```

In [ ]:

```
a *= 2; id(a) == aid
```

In [ ]:

```
c = a * 2; id(c) == aid
```

In-place operation.

In [ ]:

```
%%timeit a = np.zeros(10000000)
a *= 2
```

With memory copy.

In [ ]:

```
%%timeit a = np.zeros(10000000)
b = a * 2
```

In [ ]:

```
a = np.zeros((10, 10)); aid = id(a); aid
```

Reshaping an array while preserving its order does not trigger a copy.

In [ ]:

```
b = a.reshape((1, -1)); id(b) == aid
```

Transposing an array changes its order so that a reshape triggers a copy.

In [ ]:

```
c = a.T.reshape((1, -1)); id(c) == aid
```

`flatten`

or `ravel`

. The former always return a copy, whereas the latter only makes a copy if necessary.

In [ ]:

```
d = a.flatten(); id(d) == aid
```

In [ ]:

```
e = a.ravel(); id(e) == aid
```

In [ ]:

```
%timeit a.flatten()
```

In [ ]:

```
%timeit a.ravel()
```

In [ ]:

```
n = 1000
```

In [ ]:

```
a = np.arange(n)
ac = a[:, np.newaxis]
ar = a[np.newaxis, :]
```

In [ ]:

```
%timeit np.tile(ac, (1, n)) * np.tile(ar, (n, 1))
```

In [ ]:

```
%timeit ar * ac
```

Can you explain the performance discrepancy between the following two similar operations?

In [ ]:

```
a = np.random.rand(5000, 5000)
```

In [ ]:

```
%timeit a[0, :].sum()
```

In [ ]:

```
%timeit a[:, 0].sum()
```

You'll find all the explanations, figures, references, and much more in the book (to be released later this summer).

IPython Cookbook, by Cyrille Rossant, Packt Publishing, 2014 (500 pages).