Python IS slow ! [was] Re: Python too slow for real world
Tim Peters
tim_one at email.msn.com
Sun May 2 12:09:58 EDT 1999
[Michael Hudson, writes some seriously disturbed code for capturing
current bindings of non-local names]
Ooh -- that is cute!
> ...
> A word of warning: this code is nasty, *nasty*, NASTY. Possibly the
> most horrible thing you will see perpetrated in Python this year.
Watch out, or Gordon will revive a metaclass thread <wink>.
> It applies regular expressions to strings of bytecode...
Didn't need to, though. That is, string.replace would have worked as well
here. Regardless, it's vulnerable to picking up an inappropriate
bit-pattern by unlikely accident in either case, so should be made
bulletproof in that respect. Believe the attached does that (and is a bit
more frugal by appending values to the consts only if they're actually
referenced, and only once when they are).
> I made Python core repeatedly when debugging it.
That's why "new" is an undocumented module <0.1 wink>.
> However, it works. The returned functions are very fast. I wrote this
> package because I wanted to avoid both the tackiness of the `default
> argument hack' and the performance penalty of using classes to fake
> closures.
Not to mention writing functions to write functions that get dynamically
compiled -- this is a reasonable hack for expert use, and with any luck at
all Guido will make it completely useless in Python2 <wink>.
> ... [getting more extreme] ...
> The thing is, this would replace two argumented bytecode with one,
> changing the length of the codestring and you'd need to recompute
> jumps. I haven't had the bloody-mindedness to get this to work yet.
At least Skip Montanaro has written a bytecode optimizer with reusable code
for all this kind of manipulation; offhand I don't have a URL, though.
rewriting-from-scratch-is-a-noble-python-tradition<wink>-ly y'rs - tim
A safer replacement for munge_code and hardcoded VM constants:
from dis import opname, HAVE_ARGUMENT
LOAD_CONST = opname.index("LOAD_CONST")
LOAD_GLOBAL = opname.index("LOAD_GLOBAL")
del opname
def munge_code(code, vars):
codelist = list(code.co_code)
names = list(code.co_names)
consts = list(code.co_consts)
nameindex2value = {}
for name, value in vars.items():
try:
index = names.index(name)
except ValueError:
pass
else:
nameindex2value[index] = value
# Replace LOAD_GLOBAL instructions referring to names in vars w/
# LOAD_CONST instructions referring to the name's current binding.
nameindex2constindex = {}
i, n = 0, len(codelist)
while i < n:
c = codelist[i]
i = i+1
op = ord(c)
if op < HAVE_ARGUMENT:
continue
i = i+2
if op != LOAD_GLOBAL:
continue
oparg = 256 * ord(codelist[i-1]) + ord(codelist[i-2])
if not nameindex2value.has_key(oparg):
# this name wasn't in vars
continue
if nameindex2constindex.has_key(oparg):
index = nameindex2constindex[oparg]
else:
# first time this name is being replaced; create a slot
# for it in the consts vector
nameindex2constindex[oparg] = index = len(consts)
consts.append(nameindex2value[oparg])
codelist[i-3] = chr(LOAD_CONST)
codelist[i-2] = chr(index & 0xff)
codelist[i-1] = chr(index >> 8)
assert i == n
return copy_code_with_changes(
code,
consts=tuple(consts),
code=string.join(codelist, ''))
More information about the Python-list
mailing list