Yet more refactoring ;)
resolve_variable does a chunk of setup work for each invocation, checking for if the variable is a number, checking if its quoted (thus exempted from lookup rules), and finally splitting of the variable into it's component parts. The issue is that this work is utterly redundant the second time an attempt is made to resolve the variable- for loops for example.
This patch splits out a Variable class which does the common setup work up once in init, with a resolve method to do the actual resolution against a context. The actual resolve is still a good chunk of time, but for my particular usage scenario (3 level deep for loop being the main cost), this shaves just shy of 25% of the runtime off via killing the redundant work.
From a backwards compatibility standpoint, there isn't any issue- resolve_variable just becomes
def resolve_variable(arg, context):
return Variable(arg).resolve(context)
which admittedly will be slightly slower then whats in place now for simple lookups- this is offset by the greater efficiency of Variable usage within default tags/templates, and via killing off a quadratic op in resolve_variable- currently, it splits the arg, then does poplefts on the list.
Problem there is that python lists are literal arrays; you delete the first item, every item after has to be moved one to the left, thus quad in execution. Fortunately var depth isn't usually deep enough for it to rear its head.