Dumme Frage zu timeit (Übergabe von Referenzen)

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
windner
User
Beiträge: 76
Registriert: Freitag 19. Oktober 2007, 11:25

Schönen Freitag!

Ich bin in ein Chaos mit den Namespaces gestrudelt: Nämlich möchte ich mit dem timeit-Modul einige Messungen machen. Für die Messung brauche ich aber eine Referenz auf ein vorher erzeugtes Objekt. Und es gelingt mir nicht, die Referenz bis in den Code-String für timeit.Timer zu übergeben.

In der Dokumentation steht nur als Beispiel, daß man Namen aus __main__ importieren kann:

Code: Alles auswählen

>>> from timeit import Timer
>>> a = 2.0**.5    # irgendeine Referenz für die Zeitmessung
>>> t = Timer('1.0/a', 'from __main__ import a')   # irgendeine Aktion zum Messen
>>> t.timeit(1)
1.0967254638671875e-05    # funktioniert, wie erwartet
Wenn ich ausgehend davon aber die Zeitmessung in einer Funktion kapsle, ist die Referenz nicht mehr in __main__, sondern im lokalen Namensraum der Funktion (oder?):

Code: Alles auswählen

>>> def timeit_wrapper(ref):
...   print dir()    # um zu sehen, welche Namen hier sind
...   t2 = Timer('1.0/ref', 'from __main__ import ref')
...   return t2.timeit(1)
...   # das ist natürlich Blödsinn, weil's in __main__ keinen Namen "ref" gibt
...
>>> timeit_wrapper(3.14)
['ref']
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
  File "<stdin>", line 4, in timeit_wrapper
  File "/usr/lib/python2.4/timeit.py", line 161, in timeit
    timing = self.inner(it, self.timer)
  File "<timeit-src>", line 3, in inner
ImportError: cannot import name ref
Also meine banale Frage: wie bekomme ich ref in den Namensraum des timeit-Codes, respektive wie heißt der lokale Namensraum einer Funktion? (wenn ich wüsste, wie der heißt, könnte ich from dort importieren).
Oder bin ich auf dem Holzweg, und das geht alles ganz einfach?
schorsch
User
Beiträge: 18
Registriert: Montag 26. November 2007, 18:39

hm ich glaube auf variablen die innerhalb einer funktion definiert werden hat man von auserhalb keinen zugriff, korregiert mich bitte wenn ich falsch liege.

wenn sich ref nicht bei jedem aufruf der funktion ändert könntest du es sozusagen als konstante auf modulebene anlegen. ansonsten würde ich das mit

Code: Alles auswählen

t2 = Timer('1.0 / %f' % ref)
lösen, das dürfte wohl der einfachste weg sein.

falls die referenz eine instanz einer selbst erstellten klasse sein soll könntest du auch die klasse importieren

Code: Alles auswählen

t2 = Timer('1.0/ref', 'from __main__ import MeineKlasse; ref = MeineKlasse(%f)' % init)
wobei du dann eben nicht das objekt direkt sondern nur den wert bei der erzeugung (init) an deine funktion übergibst
windner
User
Beiträge: 76
Registriert: Freitag 19. Oktober 2007, 11:25

Danke, die Idee mit den Strings ist gut. Leider zeigt meine Referenz auf eine verkettete Liste mit beliebiger Tiefe, deshalb dauert schon allein die String-Umwandlung unter Umständen sehr lang. So will ich das nicht machen.

Mit globalen Variablen geht das aber, so wie du vorgeschlagen hast. Ist zwar ein seltsamer Hack, aber was soll's:

Code: Alles auswählen

# eins.py

from timeit import Timer

global_ref = None

def timeit_wrapper(ref):
	global global_ref;
	global_ref = ref
	t = Timer('1.0 / global_ref', 'from eins import global_ref')
	print t.timeit(1)

Code: Alles auswählen

>>> import eins; eins.timeit_wrapper(1.4142)
5.79357147217e-05
Problem gelöst, Danke!
Aber ich werde den Verdacht nicht los, daß das auch sauberer gehen würde. Ich weiß nur nicht, wie.

Was ich dabei gelernt habe, ist, daß man den Namen eines Moduls auch in demselben Modul verwenden kann (from eins ...). Dabei verwirrt mich folgendes: der Modul-Name ergibt sich aus dem Dateinamen des Scripts. Wenn ich also die Datei umbenenne, wird das Importieren aus eins nicht mehr hinhauen, weil das Modul dann nicht mehr so heißt.

Um dem vorzubeugen könnte man den Namen des Scripts herausfinden und dann in den Code-String für timeit.Timer einfügen. Allerdings ist das dann schon der zweite seltsame Hack. Habe ich vielleicht ein Schlüsselwort a la __this_module__ übersehen?
schorsch
User
Beiträge: 18
Registriert: Montag 26. November 2007, 18:39

hm ok, hab dabei zwar nicht an global gedacht aber ok.

__this_module__ heißt in python __name__
wenn das modul direkt gestartet wurde ist der inhalt von __name__ '__main__' ansonsten der name des moduls.
Antworten