Closures richtig anwenden

Was Closures sind steht unter Allgemeine Begriffe#C

Hier mal ein kleines Beispiel:

   1 >>> def get_storage():
   2 ...     data = [None]
   3 ...     def set(value):
   4 ...             data[0] = value
   5 ...     def get():
   6 ...             return data[0]
   7 ...     return get, set
   8 ...
   9 >>> get_data, set_data = get_storage()
  10 >>> set_data("Hallo Welt")
  11 >>> get_data()
  12 'Hallo Welt'
  13 >>> dir()
  14 ['__builtins__', '__doc__', '__name__', 'get_data', 'get_storage', 'set_data']

Ein Zugriff auf get_storage.data endet logischweise in einem AttributeError. Aber wie ist das möglich?

Zunächst muss man wissen, dass Python für jede Code Ebene (Funktionen, Klassen, Methoden...) einen eigenen Namensraum (Frame) zur Verfügung stellt. Sobald die letzte Referenz darauf verschwindet macht Python erst den Namensraum platt.

Der anonyme Namensraum, der von get_storage zur Verfügung gestellt wird, wird noch von get und set verwendet, die von der Funktion zurückgeworfen wurden.

Erst wenn set_data und get_data mit del wirklich gelöscht würden, würde auch der storage Namensraum verschwinden.

Die Liste wurde deswegen verwendet, damit die Referenz bei Neuzuweisung nicht verschwindet. Das sollte man einfach als gegeben hinnehmen, bis man es sich selbst erklären kann ;-)

Anwendungsbeispiel

   1 def config():
   2     config = {}
   3     def get(key):
   4         return config.get(key,None)
   5     def set(key, value):
   6         config[key] = value
   7     return get, set
   8 
   9 
  10 get_config_value, set_config_value = config()

Über den Sinn und Unsinn solcher Konstrukte kann man jetzt streiten :-) In manchen Fällen wird eine Klasse besser sein, aber man kann damit doch ganz lustige Sachen machen.

Closures richtig anwenden (last edited 2009-06-17 16:14:22 by localhost)