Dwemthy's Array or Eat this, Ruby!
Verfasst: Samstag 2. August 2008, 13:31
Durch die Blogsphere geistert gerade Why the Lucky Stiffs Artikel über Ruby-Metaprogrammierung, wo er in unnachahmlicher - aber recht konfuser - Weise Ruby Metaprogrammierung preist.
Ich finde, das ganze geht in Python viel einfacher :) Oder ich habe das Problem nicht verstanden. Zwei Punkte sind wichtig:
Man möchte gerne Klassen wie Prototypen definieren, sodass alle Exemplare einer Klasse automatisch gewisse Initialwerte haben:
Man möchte ein Array (das von Dwemthy) definieren, welches sich wie eine Creature verhält und alle Nachrichten, die man dem Array schickt (das ist Smalltalk- und Ruby-Sprech für Methodenaufrufe) an das erste Array-Element weiterreichen. Dazu überschreibt _why Rubys `method_missing` Methode einer Unterklasse von Array.
In Python sieht der Drache so aus:
Damit die automatische Vorbelegung von Exemplaren mit den Standardwerten möglichst einfach funktioniert und damit ich's genauso mache wie Ruby, benutze ich eine Metaklasse:
Auch das Array, das in Python natürlich eine Dwemthy's List ist, ist keine große Magie. Ich überschreibe __getattr__ um mitzubekommen, wenn nach etwas gesucht wird, das es nicht in `list` gibt. Ich muss ein bisschen aufpassen, weil es in Python nicht nur Methoden gibt, sondern Funktionen und Properties.
Der vollständige Code ist hier...
Geht es noch kürzer? Ich hätte ja gerne eine traits()-Methode innerhalb der Klasse benutzt, aber wie manipuliere ich in diese Funktion dann die Klasse? Sie existiert ja noch gar nicht, sondern es gibt nur ein namenloses Modul, an das ich AFAIK auch nicht herankomme. Evtl. könnte ich mir den Parent-Frame des aktuellen Frames holen und dort das locals-Dict, doch das ist auch häßlich. Meine erste Version hat auf die traits verzichtet, dann kann ich jedoch nicht mehr sauber Standardwerte und Methoden der Klasse unterscheiden. Ein `callable`-Test erschien mir unsauber.
Stefan
Ich finde, das ganze geht in Python viel einfacher :) Oder ich habe das Problem nicht verstanden. Zwei Punkte sind wichtig:
Man möchte gerne Klassen wie Prototypen definieren, sodass alle Exemplare einer Klasse automatisch gewisse Initialwerte haben:
Code: Alles auswählen
class Dragon < Creature
life 1340 # tough scales
strength 451 # bristling veins
charisma 1020 # toothy smile
weapon 939 # fire breath
end
In Python sieht der Drache so aus:
Code: Alles auswählen
class Dragon(Creature):
life = 1340 # tough scales
strength = 451 # bristling veins
charisma = 1020 # toothy smile
weapon = 939 # fire breath
Code: Alles auswählen
class MetaCreature(type):
def __init__(cls, name, bases, dct):
cls.__traits__ = getattr(bases[0], '__traits__', ()) + tuple(dct.pop('traits', ()))
class Creature(object):
__metaclass__ = MetaCreature
traits = ('life', 'strength', 'charisma', 'weapon')
def __init__(self):
for trait in self.__traits__: setattr(self, trait, getattr(self, trait))
Code: Alles auswählen
class DwemthysList(list):
def __getattr__(self, name):
if len(self):
value = getattr(self[0], name)
if callable(value):
def cont(*args, **kwargs):
answer = value(*args, **kwargs)
...
return answer
cont.__name__ = name
return cont
return value
Geht es noch kürzer? Ich hätte ja gerne eine traits()-Methode innerhalb der Klasse benutzt, aber wie manipuliere ich in diese Funktion dann die Klasse? Sie existiert ja noch gar nicht, sondern es gibt nur ein namenloses Modul, an das ich AFAIK auch nicht herankomme. Evtl. könnte ich mir den Parent-Frame des aktuellen Frames holen und dort das locals-Dict, doch das ist auch häßlich. Meine erste Version hat auf die traits verzichtet, dann kann ich jedoch nicht mehr sauber Standardwerte und Methoden der Klasse unterscheiden. Ein `callable`-Test erschien mir unsauber.
Stefan