Seite 1 von 1
Klassenmethoden zur Laufzeit definieren
Verfasst: Freitag 16. März 2007, 10:18
von hiasl
Hallo,
ich würde gerne soetwas wie unten programmieren, geht aber nicht. Das einzige, was ich geschaft habe ist, Funktionen im Konstruktor zu definieren und danach einem Klassenattribut zuzuweisen. Dann allerdings muss ich der Methode das Objekt selbst explizit übergeben: x.t(x). Das ist natürlich nicht schön.
Code: Alles auswählen
class X(object):
__metaclass__ = meta
x = 0
if x:
def t(self):
print "A"
else:
def t(self):
print "B"
x = X(0)
x.t() # => "B"
x = X(1)
x.t() => "A"
Falls jemand einen Tipp hat wäre ich dankbar.
Gruß
Matthias
Verfasst: Freitag 16. März 2007, 10:25
von EyDu
Vielleicht liegt es nur an dem einfachen Beispiel, aber für so etwas verwendet man normalerweise Vererbung.
Verfasst: Freitag 16. März 2007, 10:33
von hiasl
Es liegt am einfachen Beispiel ;)
Verfasst: Freitag 16. März 2007, 10:41
von BlackJack
Oder in diesem Beispiel alternativ eine Factory-Funktion die eines von zwei Objekten zurückgibt.
Oder man übergibt 'A' oder 'B' im Konstruktor und gibt dass dann entsprechend aus.
Da das Beispiel aber viel zu einfach ist, kann man das nicht sagen. Welches Problem soll denn gelöst werden? Und bitte das Problem nicht in Form einer Lösung beschreiben, sondern wirklich das *Problem* selbst.
Verfasst: Freitag 16. März 2007, 11:03
von hiasl
Ich will unterschiedliche Dinge in einer Klasse kapseln, unter möglichst hoher Wahrung von Transparenz. Das bedeutet, dass mit "isinstance", "instanceof" & co. keine Unterscheidung möglich sein soll.
Aus diesen Gründen scheiden Vererbung und Factories aus.
Deshalb zurück zur problembeschreibenden Fragestellung:
Kann man "Klassenmethoden zur Laufzeit definieren"?
Was ich bisher hinbekommen habe ist:
Code: Alles auswählen
class X(object):
define __init__(self, x):
if x:
def t(self):
print "A"
else:
def t(self):
print "B"
self.t = t
y = X(1)
y.t(y) #=> A
y = X(0)
y.t(y) #=> B
Wie man sieht, muss dann aber das Objekt als Instanz übergeben werden.
Vielleicht kann man ja eine Funktion als Objektfunktion registrieren?
Verfasst: Freitag 16. März 2007, 11:18
von BlackJack
Du versuchst da etwas zu machen was unpythonisch ist -- Stichwort "duck typing". Der Typ sollte egal sein, wichtig ist das Verhalten des Objekts.
Verfasst: Freitag 16. März 2007, 11:38
von hiasl
Was meine Frage leider nicht beantwortet.
Im übrigen ist eine solche Implementierung selbstverständlich pythonic. Denn meine Klasse sieht nicht nur aus wie eine Ente, quackt wie eine Ente, sondern da steht sogar noch "Ente" drauf".
Verfasst: Freitag 16. März 2007, 11:56
von Zap
sondern da steht sogar noch "Ente" drauf".
das macht es ja eben unpythonic.
duck-typing ist wenn Hund drauf stehen würde und der sich wie die Ente verhält
Ich weiß, das hilft bei deinem Problem nicht weiter, aber oft ist es besser nochmal drüber nachzudenken wie wichtig das mit dem gleichen "aussehen" deiner instanzen ist
Verfasst: Freitag 16. März 2007, 12:20
von hiasl
Mir ist klar, was "Duck typing" ausmacht. Deshalb nochmal:
Meine Klasse ist konform zu dem Paradigma, da die Menge aller Objekte, die sich wie Enten verhalten, eine Obermenge der Objekte ist, die sich wie Enten verhalten und bei denen zusätzlich "Ente" draufsteht.
=> Wenn man auf der Obermenge pythonic arbeiten kann, kann man das folglich auch mit der Untermenge. Das Ganze verursacht erst Probleme wenn man auf der Obermenge operiert und ein Kriterium der Untermenge nutzt - das ist der vorher angesprochene Kontext.
Im übrigen bleibt es jedem selbst überlassen, ob er pythonic programmiert oder nicht. Ich brauche das zum Beisipiel, um Geräte wie Achsen, Roboter, etc. über .dlls, .so oder sockets einzubinden. Denen kann ich noch so oft sagen, "quacke" wie eine Ente. Sie tuns nicht ;). Was an dieser Stelle erreicht werden soll, ist eine absolute Trennung zwischen einer Steuerungsarchitektur und den angeschlossenen Geräten. Und dazu gehört auch, dass ein Anwendungsprogrammierer "unpythonic" programmieren könnte. Ich kann diesen Fall nicht ausschließen und auch nicht jeden Programmierer zu einem Kurs in "duck typing" schicken.
Jedes Paradigma stößt an Grenzen, wenn mit anderen Systemen interagiert werden muss.
Verfasst: Freitag 16. März 2007, 12:22
von Dill
Verfasst: Freitag 16. März 2007, 12:43
von BlackJack
Na dann korrigiere ich erstmal Deine Frage: "Ist es möglich Instanzmethoden zu einem Objekt hinzuzufügen?", denn an die Klasse möchtest Du die ja nicht binden.
Die Antwort ist: "Ja."
Und zu Deinem Problem dass Du beschreibst: Das hört sich nach einem Fall für Komposition an.
Das mit den Unter- und Obermengen ist nett, aber das unpythonische ist die Verwendung von `isinstance()`. Das muss ja wohl irgendwo verwendet werden um diesen ganz bestimmten Typ zu testen, ansonsten gäb's das Problem nicht und man könnte auch den quakenden Hund benutzen.
Wieso kann man den Programmierern nicht die idiomatische Verwendung einer Programmiersprache beibringen? Wenn Du eine Sprache willst, in der man sich nur sehr schwer in den Fuss schiessen kann, bist Du bei Python falsch und solltest lieber eine "discipline & bondage"-Sprache wie Java verwenden. Von einem Python-Programmierer wird im allgemeinen erwartet, dass er weiss was er da tut. Das ist der Preis den man für die Flexibilität und Dynamik zahlen muss.
Verfasst: Freitag 16. März 2007, 13:08
von hiasl
BlackJack hat geschrieben:Na dann korrigiere ich erstmal Deine Frage: "Ist es möglich Instanzmethoden zu einem Objekt hinzuzufügen?", denn an die Klasse möchtest Du die ja nicht binden.
der Punkt geht an Dich :)
BlackJack hat geschrieben:
Das mit den Unter- und Obermengen ist nett, aber das unpythonische ist die Verwendung von `isinstance()`. Das muss ja wohl irgendwo verwendet werden um diesen ganz bestimmten Typ zu testen, ansonsten gäb's das Problem nicht und man könnte auch den quakenden Hund benutzen.
Der Punkt nicht. Ich habe nie behauptet, dass ich "instanceof" _verwende_, sondern dass es _möglich_ sein soll. Somit _kann_ das Problem bestehen, muss aber nicht. Wenn es entsteht, soll es transparent sein.
Wieso bietet Python eigentlich "unpythonische" Funktionen an? Kennen die Entwickler nicht die idiomatische Verwendung ihrer Sprache? Sollte man vielleicht van Russum zur Nachschulung schicken?
Verfasst: Freitag 16. März 2007, 13:09
von jens
Wozu das immer auch gut ist... Wie wäre es damit:
Code: Alles auswählen
class X(object):
def __init__(self, mode):
if mode == 0:
self.t = self.t_A
else:
self.t = self.t_B
def t_A(self):
print "A"
def t_B(self):
print "B"
x = X(0)
x.t() # => "B"
x = X(1)
x.t() # => "A"
Verfasst: Freitag 16. März 2007, 13:09
von hiasl
Besten Dank, das war, was ich wollte :)
Verfasst: Freitag 16. März 2007, 14:02
von BlackJack
hiasl hat geschrieben:BlackJack hat geschrieben:
Das mit den Unter- und Obermengen ist nett, aber das unpythonische ist die Verwendung von `isinstance()`. Das muss ja wohl irgendwo verwendet werden um diesen ganz bestimmten Typ zu testen, ansonsten gäb's das Problem nicht und man könnte auch den quakenden Hund benutzen.
Der Punkt nicht. Ich habe nie behauptet, dass ich "instanceof" _verwende_, sondern dass es _möglich_ sein soll.
Also wird es doch irgendwo verwendet, wäre dem nicht so, löst Du ein Problem das es nicht gibt.
Wieso bietet Python eigentlich "unpythonische" Funktionen an? Kennen die Entwickler nicht die idiomatische Verwendung ihrer Sprache?
Och bitte. Man kann so ziemlich jedes Feature zweckentfremden. "Pythonische" Verwendung von Instanzmethoden, die zur Laufzeit einem Objekt hinzugefügt werden, wäre zum Beispiel einem Hund, der nicht quaken kann, eine solche Methode dynamisch zu verpassen, damit er irgendwo als Ente durchgeht und nicht damit dort dann ein `instanceof(obj, Ente)` funktioniert.
Idiomatische Verwendung bedeutet ja gerade, dass es nicht von der Sprache so erzwungen wird, sondern dass etwas in der Regel so formuliert wird, weil es der Philosophie der Sprache entspricht. Die meisten Sachen kann man auch gar nicht erzwingen, weil sie formal gar nicht erfasst werden. Selbst bei statischeren Sprachen geht das nicht.
Verfasst: Freitag 16. März 2007, 14:17
von hiasl
Für den Fall, dass jemand ein ähnliches Problem hat, hier eine funktionierende Lösung:
Code: Alles auswählen
from new import instancemethod
class X(object):
def __init__(self, x):
if x:
def t(self):
print "A"
else:
def t(self):
print "B"
self.__setattr__('t', instancemethod(t, self, X))
X(1).t()
X(0).t()
@BlackJack: Die Diskussion führt zu keinem Ergebnis - weder für Dich noch für mich. Trotzdem Danke und noch einen schönen Tag :)
Verfasst: Freitag 16. März 2007, 14:19
von jens
Warum nicht so:
Code: Alles auswählen
class X(object):
def __init__(self, x):
if x:
def t():
print "A"
else:
def t():
print "B"
self.t = t
X(1).t()
X(0).t()
EDIT: Ah, ok... wenn man zugriff auf self haben möchte, geht's so nicht

Verfasst: Freitag 16. März 2007, 14:47
von sape
BlackJack hat geschrieben:Oder in diesem Beispiel alternativ eine Factory-Funktion die eines von zwei Objekten zurückgibt.
Sorry wenn ich hier so reinplatze. Was sind Factory-Funktion?

Sowas wie Closures?
Verfasst: Freitag 16. März 2007, 14:54
von hiasl
sape hat geschrieben:BlackJack hat geschrieben:Oder in diesem Beispiel alternativ eine Factory-Funktion die eines von zwei Objekten zurückgibt.
Sorry wenn ich hier so reinplatze. Was sind Factory-Funktion? :? Sowas wie Closures?
Eine Factoryfunktion instantiiert ganz einfach in Abhänigkeit von Parametern Objekte von nunterschiedlichen Klassen. Damit hast Du einen zentralen Objekterzeuger und musst selbst nicht immer Fallunterscheidungen implementieren.
Gern zitiertes Beispiel:
Du kannst für jede Pizza eine eigene Klasse schreiben.
Den Pizzabäcker implementierst Du als Factory, der bei Bestellung der Pizza in Abhängigkeit des Pizzanamens die richtige Pizza erzeugt.