↑Rezepte
Wir betrachten Eierzahlen, die sich verhalten wie gewöhnliche ganze Zahlen, aber von diesen zu unterscheiden sind. Es ist eine allgemeine Nachfolgerabbildung zu formulieren, die sowohl für gewöhnliche als auch für Eierzahlen definiert ist. Weiterhin soll diese Abbildung polymorph formuliert sein, dergestalt dass die passende Abbildung über einen Dispatch ermittelt wird. Innerhalb der Abbildung soll sie nochmals aufgerufen werden, so dass ein wechselseitiger Dispatch stattfinden kann. Ausgangspunkt ist so gesagt das folgende Programm:
# Datei egg.py class Egg: def __init__(self, value): self.value = value def __repr__(self): return "Egg({})".format(repr(self.value)) def __succ__(self): return Egg(succ(self.value)) # Datei succ.py def succ(x): return x + 1 if isinstance(x, int) else x.__succ__() # Datei app.py from egg import Egg from succ import succ print(succ(Egg(0)))
Hier stellt sich das Problem, dass succ
in
Egg
unbekannt ist. Man könnte also succ
einfach importieren. Wir würden nun aber gerne haben, dass
egg
nichts über succ
wissen braucht
und umgekehrt succ
nichts über egg
wissen
braucht.
Ein Lösungsansatz besteht in der Formulierung eines parametrisierten Moduls. Hier dürfen dem Modul beim Laden zusätzliche Parameter gegeben werden.
# Datei egg.py def load(succ = None): class Egg: def __init__(self, value): self.value = value def __repr__(self): return "Egg({})".format(repr(self.value)) if succ != None: def __succ__(self): return Egg(succ(self.value)) Egg.__succ__ = __succ__ return Egg # Datei succ.py def succ(x): return x + 1 if isinstance(x, int) else x.__succ__() # Datei app.py import egg from succ import succ Egg = egg.load(succ = succ) print(succ(Egg(0)))
Parametrisierung kann alternativ über globale Variablen
stattfinden. Im der nächsten Formulierung ist module_table
eine von jedem Modul aus zugängliche globale Variable.
Es tut sich hier leider das kleine Defizit auf, dass die Reihenfolge,
in der die Module importiert werden, nun eine Rolle spielt, was dem
Nutzer der Programmierschnittstelle nicht unbedingt klar sein muss.
# Datei config.py module_table = {} # Datei egg.py import config class Egg: def __init__(self, value): self.value = value def __repr__(self): return "Egg({})".format(repr(self.value)) if "succ" in config.module_table: succ = config.module_table["succ"].succ def __succ__(self): return Egg(succ(self.value)) Egg.__succ__ = __succ__ # Datei succ.py import config config.module_table[__name__] = __import__(__name__) def succ(x): if isinstance(x, int): return x + 1 else: return x.__succ__() # Datei app.py from succ import succ from egg import Egg print(succ(Egg(0)))
Eine recht ordentliche Konstruktion findet sich, wenn man für die zusätzliche Funktionalität eine extra Klasse definiert, die die gewöhnliche Eierklasse als Basis hat. Es verbleibt das kleine Defizit, dass bei der Nutzung der Programmierschnittstelle die passende Konfiguration gewählt werden muss.
# Datei egg.py class Egg: def __init__(self, value): self.value = value def __repr__(self): return "Egg({})".format(repr(self.value)) # Datei eggsucc.py from egg import Egg as PlainEgg from succ import succ class Egg(PlainEgg): def __succ__(self): return Egg(succ(self.value)) # Datei succ.py def succ(x): return x + 1 if isinstance(x, int) else x.__succ__() # Datei app.py from eggsucc import Egg from succ import succ print(succ(Egg(0)))