def f(list):
return ''.join([chr(l) for l in list])Python Patterns - An Optimization Anecdote
21–30 of 45 posts
Re: Python Patterns - An Optimization Anecdote
#22Why not just: def f(list): return ''.join([chr(l) for l in list])
Re: Python Patterns - An Optimization Anecdote
#23I hope that one day soon our compilers will be smart enough to optimize simple things like this automatically, so we can focus more on writing for clarity. This seems like exactly the kind of thing a next-gen compiler should be able to optimize.
I'm not sure it's so possible, considering the dynamic nature of Python. Consider one of the biggest problems - dynamic lookups. Calling a function like "chr", which is looked up dynamically and found in the global scope each time, takes a lot of time. Just adding a local variable which has the same value (i.e. lchr = chr) already gives a speedup. How can an optimizer fix this? Technically, a new lookup must be perfo…
Shouldn't that be just one or two pointer-dereferences? Or is Python putting globals in hash-table and looking them up each and every time?
Re: Python Patterns - An Optimization Anecdote
#24Why not just: def f(list): return ''.join([chr(l) for l in list])
However, before that, there was the string module, which had the join() function. This article probably relates to it in some way; I think that either it predates string.join (I'm not sure when that was added to Python, but it's been around since at least 1.4), or it clarifies how it was implemented.
The author is Guido van Rossum, by the way (another thing that isn't mentioned in the article).
Re: Python Patterns - An Optimization Anecdote
#25Earlier quoted context omitted.
I'm not sure it's so possible, considering the dynamic nature of Python. Consider one of the biggest problems - dynamic lookups. Calling a function like "chr", which is looked up dynamically and found in the global scope each time, takes a lot of time. Just adding a local variable which has the same value (i.e. lchr = chr) already gives a speedup. How can an optimizer fix this? Technically, a new lookup must be perfo…
> Calling a function like "chr", which is looked up dynamically Shouldn't that be just one or two pointer-dereferences? Or is Python putting globals in hash-table and looking them up each and every time?
I don't know the details, but I assume that some of the Python compiler projects do make assumptions like this, i.e. they can compile to faster code if you don't shadow or outright overwrite builtins, etc.
Re: Python Patterns - An Optimization Anecdote
#26Earlier quoted context omitted.
> Calling a function like "chr", which is looked up dynamically Shouldn't that be just one or two pointer-dereferences? Or is Python putting globals in hash-table and looking them up each and every time?
The latter; otherwise it wouldn't be dynamic. :-) I don't know the details, but I assume that some of the Python compiler projects do make assumptions like this, i.e. they can compile to faster code if you don't shadow or outright overwrite builtins, etc.
Re: Python Patterns - An Optimization Anecdote
#27Why not just: def f(list): return ''.join([chr(l) for l in list])
sikanda-13:30:02:/tmp$ python f.py
[...]
f1 0.07
f2 0.12
f3 0.07
f4 0.06
f5 0.09
f6 0.04
f7 0.02
f8 0.07
Original code linked in the article: http://www.python.org/doc/essays/f.pyRe: Python Patterns - An Optimization Anecdote
#28Why not just: def f(list): return ''.join([chr(l) for l in list])
This would be my default approach as well. I'd be interested to see how it compares-- my guess is that it would be equivalent to or slightly faster than f6(), and slower than the version that uses the array library.
Re: Python Patterns - An Optimization Anecdote
#29I once found myself writing a python program to calculate Poker hands. It was pretty fun to write - it generated, for any given hand you hold, every possible way the game can go forward, and generated statistics about how many times you win (against 1 opponent only, who could be holding anything.) The program initially ran for 20 minutes on each hand. I worked a day on optimizing it, and got it down to around 1-2 min…
Also, and this is just on a more minor, pedantic note, list comprehensions basically are regular for loops, except with the use of the list-append opcode instead of a getattr-call pair. This produces a minor speedup, but it's nothing to write home about, honest. (using a different pastebin because it has a feature I needed): http://ideone.com/dT1LG . The story is a bit different on 3.x, where list comps are implemented very differently: http://ideone.com/58FGZ
Re: Python Patterns - An Optimization Anecdote
#30Why not just: def f(list): return ''.join([chr(l) for l in list])
This would be my default approach as well. I'd be interested to see how it compares-- my guess is that it would be equivalent to or slightly faster than f6(), and slower than the version that uses the array library.
In [24]: timeit ''.join(map(chr, ll))
100000 loops, best of 3: 3.91 us per loop
In [25]: timeit ''.join([chr(i) for i in ll])
100000 loops, best of 3: 5.85 us per loop
In [26]: timeit ''.join(chr(i) for i in ll)
100000 loops, best of 3: 7.79 us per loop