Rewrite redundant codepatterns introduced by py2 -> py3 conversion
Created by: nthykier
The automated python2 -> python3 converter creates some suboptimal code patterns in some cases, notably in its handling of dicts.
This commit handles the following cases:
-
"if x in list(y.keys()):" => "if x in y:"
The original code is neuters the O(1) lookup effeciency of a dict by turning it into a list. This occurs a O(n) in converting it to a list and then another O(n) for the lookup. When done in a loop, this becomes O(n * m) rather than the optimal O(m).
-
"for x in list(y.keys()):" => "for x in y:" OR "for x in list(y):"
A dict (y in these cases) operates as an iterator over keys in the dict by default. This makes the entire "list(y.keys())" dance redundant in most cases. In a some cases, scour modifies the dict while iterating over it and in those cases, we need a "list(y)" (but not a "y.keys()").
The benefit of this differs between python2 and python3. In python3, we basically "only" avoid function call. In python2, y.keys() generates a list, so here we avoid generating a "throw-away list".
The test suite succeed both with "python testscour.py" and "python3 testscour.py" (used 2.7.14+ and 3.6.4 from Debian testing).
On a 341kB flame-graph generated by "nytprof" (a perl profiler), this commit changes the runtimes of scour from the range 3.39s - 3.45s to 3.27s - 3.35s making it roughly 3% faster in this case (YMMV, particularly with different input). The timings were recorded using the following command line:
time PYTHONPATH=. python3 -m scour.scour --enable-id-stripping
--shorten-ids --indent=none --enable-comment-stripping
-i input.svg -o output.svg
This was used 5 times with and 5 times without the patch picking the worst and best time to define the range. The runtime test was only preformed on python3.
All changed lines where found with: grep -rE ' in list[(].*[.]keys[(][)][)]:'
Signed-off-by: Niels Thykier niels@thykier.net