hgrecco/pint — pull request #166 by jbmohler (2014-07-02 14:41:46+00:00)
Title: optimizations ... mainly by refactoring some recursions

The motivation of this pull request is to improve the speed of converting quantities to different units. Profiling reveals that the `isinstance` calls in the methods of UnitsContainer are not particularly fast and are called very often. I considered a PR which removes those `isinstance` calls since they are arguably valuable only for debugging, but they are very nice to have so that code fails early. Instead I think this PR is a more enlightened version which (principally) rewrites get_base_units and get_dimensionality with a helper function for the recursion and constructs the new UnitsContainer once at the end.

The appears to obviate the need for `_base_units_cache` and so I've removed it. A few other easy items presented themselves as well which are clear in the commits.

I illustrate the performance improvements here:

```
>>> import pint
>>> import time
>>> ureg = pint.UnitRegistry()
```

```
>>> q = 34.*ureg.cm
>>> m = ureg.m
>>> s = time.time()
>>> x = [q.to(m) for _ in range(100)]
>>> time.time() - s # doctest: +ELLIPSIS
0....
```

New: 0.0089; Old: 0.0121

```
>>> q = 34.*ureg.cm**3*ureg.g
>>> m = ureg.m**3*ureg.mg
>>> s = time.time()
>>> x = [q.to(m) for _ in range(100)]
>>> time.time() - s # doctest: +ELLIPSIS
0....
```

New: 0.0144; Old: 0.0310

```
>>> q = 34.*ureg.V
>>> m = ureg.mV
>>> s = time.time()
>>> x = [q.to(m) for _ in range(100)]
>>> time.time() - s # doctest: +ELLIPSIS
0....
```

New: 0.0205; Old: 0.0746

As you can see the performance improvement grows as the structure of the unit becomes more complex, but even the base case has substantial improvement.