Danke für die Erläuterung!
Ich habe noch weiter experimentiert und - siehe da - auch ohne Griff in die C-Kiste lässt sich noch was herausholen, wenn man deine intelligente Punkt-Klasse verwendet:
Code: Alles auswählen
import random
import time
from operator import itemgetter
class Punkt(tuple):
__slots__ = ()
def __new__(cls):
return tuple.__new__(cls, (random.randrange(3), random.randrange(3)))
x = property(itemgetter(0))
y = property(itemgetter(1))
def distance(p, q):
return ((p[0] - q[0]) ** 2 + (p[1] - q[1]) ** 2) ** 0.5
class DistDict(dict):
def __missing__(self, key):
v = self[key] = distance(*key)
return v
def matchinglaenge1(punkte):
geslaenge=0
for nummer in xrange(1, len(punkte),2):
punkt1 = punkte[nummer]
punkt2 = punkte[nummer-1]
geslaenge += ((punkt2.x-punkt1.x)**2+(punkt2.y-punkt1.y)**2)**0.5
return geslaenge
def matchinglaenge2(punkte, d=DistDict()):
return sum(d[k] for k in zip(punkte[::2], punkte[1::2]))
def matchinglaenge3(punkte):
dist = {}
geslaenge = 0
for k in xrange(0,len(punkte),2):
pair = punkte[k], punkte[k+1]
try:
laenge = dist[pair]
except KeyError:
dist[pair] = laenge = distance(*pair)
geslaenge += laenge
return geslaenge
# ----------
punkte = [Punkt() for k in xrange(34000)]
t0 = time.time()
matchinglaenge1(punkte)
print time.time()-t0
t0 = time.time()
matchinglaenge2(punkte)
print time.time()-t0
t0 = time.time()
matchinglaenge3(punkte)
print time.time()-t0
Ergibt bei mir:
Anmerkungen:
Die Variante (nicht im Code, weil ineffizient) mit frozensets bringt nichts; zwar kann man dann noch öfter auf die schon berechneten Kantenlängen zurückgreifen, aber die Erzeugung und das Arbeiten mit den Mengen kostet mehr Zeit, als man damit gewinnt.
Wenn man in der Funktion des OP den Zugriff über die Tupel-Indizes statt über die Objektattribute vornimmt, wird es ebenfalls ein ganzes Stück schneller.
Die Variante mit dem zip() funktioniert mit dieser Klassendefinition jetzt auch, weil Klassenobjekte eben auch Tupel sind.
Allerdings: So wie ich Honk verstanden habe, hat er keinen Einfluss auf die Punkt-Klasse, so dass diese eben nicht von Tupeln abgeleitet werden und kein Zugriff über Indizes möglich ist. Damit ist der Performance-Gewinn durch die intelligente Klassendefinition wieder dahin.