On Fri, May 28, 2021 at 12:13 PM Brendan Barnwell brenbarn@brenbarn.net wrote:
On 2021-05-27 13:15, Chris Angelico wrote:
Hmmmmmmmm.... let's see.
def merge_shortest(things):
... len=len ... ... ...
merge_shortest([])
Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 2, in merge_shortest UnboundLocalError: local variable 'len' referenced before assignment
Okay, yeah, mea culpa. As several people pointed out that doesn't
work. But `len_ = len` does work. However, that doesn't change the calculus at all for me. My point wasn't about using the exact same variable name. It's that ANY ability to create a local variable that is a fast-lookup shortcut for a global one is enough. My point is that manually creating fast-lookup local-variable shortcuts is inherently a performance hack and there's no real use in making it slightly nicer-looking.
The change of variable name is significant, though. It means that this is no longer a minor change to the function's header; in order to use this optimization, you have to replace every use of the name "len" with "len_" (or "_len"). That isn't necessarily a deal-breaker; I've seen code that optimizes method lookups away by retaining the callable (eg "ap = some_list.append"), so there's uses for that kind of rename; but refactoring becomes harder if you have to be aware of whether you're using the optimized version or not.
Why should a performance-improving hoist look ugly? It's a perfectly normal thing to do - calculate something once and reuse the value, because you know that it won't change (or don't care if it changes). It's not a "hack" - it's a legit method of saving effort.
(Some day I'll learn how to do this in real life. Why can't I buy just one egg, and then reuse the same egg for every meal?)
ChrisA