Langweilige Methodenüberschreibung

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.
Benutzeravatar
Goswin
User
Beiträge: 363
Registriert: Freitag 8. Dezember 2006, 11:47
Wohnort: Ulm-Böfingen
Kontaktdaten:

Ich schreibe manchmal etwas in der folgender Art:

Code: Alles auswählen

class Sonderzahl(int):
  def __new__(cls,zahl=0):
    return  super(Sonderzahl,cls).__new__(Sonderzahl,zahl)
  #
  #einzige wirklich abgeänderte Methode (nur ein Beispiel):
  def __str__(inst): return "S(%i)"%inst
  #
  def __add__(inst,szahl):
    assert isinstance(szahl,Sonderzahl)
    return Sonderzahl(super(Sonderzahl,inst).__add__(szahl))
  #
  def __sub__(inst,szahl):
    assert isinstance(szahl,Sonderzahl)
    return Sonderzahl(super(Sonderzahl,inst).__sub__(szahl))
  #
  ...viele_weitere_Methoden_der_Klasse_int...
Vorausgesetzt, man möchte auf die gesamte Funktionalität der Grundklasse nicht verzichten; ist es dann unvermeidlich, alle Methoden der Grundklasse zu überschreiben, nur weil man ein paar wenige abändern oder hinzufügen möchte?
Zuletzt geändert von Goswin am Donnerstag 2. April 2009, 15:28, insgesamt 1-mal geändert.
derdon
User
Beiträge: 1316
Registriert: Freitag 24. Oktober 2008, 14:32

Prober mal aus, was passiert, wenn man nur eine Methode überschreibt :wink: Trau dich doch einfach mal, was soll schon schlimmes passieren?
Benutzeravatar
Goswin
User
Beiträge: 363
Registriert: Freitag 8. Dezember 2006, 11:47
Wohnort: Ulm-Böfingen
Kontaktdaten:

@derdon: Bereits geschehen. Sobald ich ein Operator oder eine Funktion für eine Sonderzahl aufrufe, ist das Ergebnis ein gewöhnliches int, und die zusätzliche Funktionalität ist futsch.

Code: Alles auswählen

assert isinstance( Sonderzahl(2)*Sonderzahl(3), Sonderzahl )
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Modifiziere dass Verhalten doch einfach über __getattr__ (nicht zu verwechseln mit __getattribute__ welches man nicht so einfach überschreiben sollte es sei den man weiß wirklich was man tut).
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Das was du willst ist eher ein Adapter und keine Vererbung. Das lässt sich recht einfach über Metaklassen lösen.
Das Leben ist wie ein Tennisball.
Benutzeravatar
Trundle
User
Beiträge: 591
Registriert: Dienstag 3. Juli 2007, 16:45

DasIch hat geschrieben:Modifiziere dass Verhalten doch einfach über __getattr__ (nicht zu verwechseln mit __getattribute__ welches man nicht so einfach überschreiben sollte es sei den man weiß wirklich was man tut).
Das funktioniert nicht, weil die ganzen Methoden bei New-Style-Klassen im Typ, also der Klasse, vorhanden sein müssen.

Mit Metaklassen ginge es, siehe auch den Thread zu römischen Zahlen, den es mal hier im Forum gab.
"Der Dumme erwartet viel. Der Denkende sagt wenig." ("Herr Keuner" -- Bertolt Brecht)
Benutzeravatar
Goswin
User
Beiträge: 363
Registriert: Freitag 8. Dezember 2006, 11:47
Wohnort: Ulm-Böfingen
Kontaktdaten:

OK, ich versuche einmal zu lernen, was eine Metaklasse ist :shock:. Macht euch auf Anfängerfragen gefasst, denn ich habe so einige Schwierigkeiten mit dem Sprachgebrauch der Handbücher.

Rein empirisch stelle ich zunächst einmal fest, dass bei allen meinen Objekten folgende Beziehung gilt:
type(X) == X.__class__
(1) Ist das wirklich IMMER so?
(2) Wenn ja, Ist DAS die sogenannte Metaklasse von X? *befürcht nein*

Nachdem ich mir so viel Mühe gegeben habe, die Typen von den Klassen zu trennen, werden beide nun wieder in denselben Topf geworfen :(.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

(1) Ja
(2) Richtig, das sind keine Metaklassen.

Such mal im Forum, wie von Trundle vorgeschlagen, nach "römischen Zahlen". Ganz am Ende des Threads sind Beispiele.
Das Leben ist wie ein Tennisball.
BlackJack

@Goswin:

1) Nein, weil nicht jedes Objekt ein `__class__`-Attribut hat. "Classic"-Klassen zum Beispiel nicht:

Code: Alles auswählen

In [778]: class A: pass
   .....:

In [779]: A.__class__
---------------------------------------------------------------------------
<type 'exceptions.AttributeError'>        Traceback (most recent call last)

/home/bj/<ipython console> in <module>()

<type 'exceptions.AttributeError'>: class A has no attribute '__class__'
Wie hast Du Typen und Klassen denn "getrennt"? Das ist in Python im Grunde das gleiche. Mittels Klassen definiert man eigene Typen. Man kann die beiden Begriffe synonym verwenden.

Klassen sind Baupläne für Objekte. Klassen selbst sind auch Objekte. Metaklassen sind also Baupläne für Objekte vom Typ Klasse. Wenn also ein Klassenobjekt erstellt wird, für das eine Metaklasse angegeben wurde, dann bekommt diese Metaklasse die Klasse und kann sie verändern.
Benutzeravatar
Goswin
User
Beiträge: 363
Registriert: Freitag 8. Dezember 2006, 11:47
Wohnort: Ulm-Böfingen
Kontaktdaten:

EyDu hat geschrieben:Das was du willst ist eher ein Adapter und keine Vererbung.
...
Such mal im Forum, wie von Trundle vorgeschlagen, nach "römischen Zahlen". Ganz am Ende des Threads sind Beispiele.
Meinst du folgenden Beitrag?
http://svn.berlios.de/viewcvs/docutils/ ... iew=markup
Meinst du vielleicht, ich sollte nicht vorschnell eine Klasse definieren, sondern eher eine Funktion, damit wäre mir besser gedient? Es muss ja nicht unbedingt eine Klasse sein.
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Nein, eher nicht, denn du solltest dir ein Beispiel mit Metaklassen ansehen und das was du rausgeholt hast nutzt doch nichteinmal Klassen, also wie soll das gehen, dass man darueber lernt wie Metaklassen funktionieren?
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
Goswin
User
Beiträge: 363
Registriert: Freitag 8. Dezember 2006, 11:47
Wohnort: Ulm-Böfingen
Kontaktdaten:

BlackJack hat geschrieben:Wie hast Du Typen und Klassen denn "getrennt"? Das ist in Python im Grunde das gleiche. Mittels Klassen definiert man eigene Typen. Man kann die beiden Begriffe synonym verwenden.
Tja, wenn du, Blackjack, dich dafür interessierst, wie ich auf meine falschen Ideen gekommen bin, kann ich dir unter anderem "Eiffel-Erbauer" Bertrand Meyer zitieren, der meine erste objektorienterte Erfahrung verschuldet hat:
Bertrand Meyer, Object Oriented Software Construction, 2.ed.,S.166, hat geschrieben:A class is a model, and an object is an instance of such a model. This property is so obvious that it would normally deserve no comments beyond the preceeding definitions; but it has been the victim of so much confusion in the more careless segment of the literarture that we must take some time to clarify the obvious.
Alles grundsätzlich richtig, aber es entsteht der Eindruck, dass eine Klasse nie und nimmer ein Objekt ist. Wenn dann Python selber einige der Klassen "class" nennt und andere synonyme Klassen "type" nennt, dann versucht man natürlich, beides auseinanderzuhalten, und setzt voraus, dass da irgendein wichtiger Unterschied ist. Ein Unterschied scheint tatsächlich gegeben zu sein, aber ein unwichtiger: ich glaube jetzt, "type" wird eher für eingebaute Klassen (oder eingebaute Metaklassen) verwendet, und "class" eher für benutzerdefinierte Klassen (oder benutzerdefinierte Metaklassen).

Meine Hauptprobleme sind nun:

(1) Wie unterscheide ich, ob ein Objekt X eine Metaklasse ist oder nicht?
(2) Ist das "object", von dem alle anderen Klassen und sogar type erben (siehe type.__mro__), nun eine Metaklasse oder nicht?
(3) Erben Metaklassen manchmal ausschließlich von gewöhnlichen Klassen (siehe type.__mro__)?
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Goswin hat geschrieben:Alles grundsätzlich richtig, aber es entsteht der Eindruck, dass eine Klasse nie und nimmer ein Objekt ist.
Aber du solltest doch wissen, das in Python alles was an einen Namen gebunden werden kann, ein Objekt ist.
Goswin hat geschrieben:Wenn dann Python selber einige der Klassen "class" nennt und andere synonyme Klassen "type" nennt, dann versucht man natürlich, beides auseinanderzuhalten, und setzt voraus, dass da irgendein wichtiger Unterschied ist. Ein Unterschied scheint tatsächlich gegeben zu sein, aber ein unwichtiger: ich glaube jetzt, "type" wird eher für eingebaute Klassen (oder eingebaute Metaklassen) verwendet, und "class" eher für benutzerdefinierte Klassen (oder benutzerdefinierte Metaklassen).
class/type ist nur bei Old/New-Style-Klassen von Bedeutung. Erstere solltest du gar nicht nutzen, von daher kannst du sagen dass alle Metaklassen von ``type`` erben. Aber das Klassen Typen sind, das ist so oder so wahr (egal ob nun class/type). In Python merkt man das weniger, aber wenn man Java nimmt, wo man alle Typen deklarieren muss dann merkt man schnell dass zwischen ``int`` und ``MyClass`` kein sonderlicher Unterschied besteht (ahem, ok, schlechtes Beispiel).
Goswin hat geschrieben:(1) Wie unterscheide ich, ob ein Objekt X eine Metaklasse ist oder nicht?
Eine (New-Style) Metaklasse erbt von type, an irgendeiner Stelle der MRO.
Goswin hat geschrieben:(3) Erben Metaklassen manchmal ausschließlich von gewöhnlichen Klassen (siehe type.__mro__)?
Ich denke nicht. ``type`` hat doch in ``__mro__`` eine Metaklasse, nämlich sich selbst :)
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
Goswin
User
Beiträge: 363
Registriert: Freitag 8. Dezember 2006, 11:47
Wohnort: Ulm-Böfingen
Kontaktdaten:

Leonidas hat geschrieben:Aber du solltest doch wissen, das in Python alles was an einen Namen gebunden werden kann, ein Objekt ist.
Interessante Erklärung. Im Python-Umfeld nehme ich das jetzt bis auf weiteres als Definition von Objekt.
Leonidas hat geschrieben: class/type ist nur bei Old/New-Style-Klassen von Bedeutung. Erstere solltest du gar nicht nutzen, von daher kannst du sagen, dass alle Metaklassen von ``type`` erben.
Ich benutze immer nur Newstyle-Klassen. Trotzdem lesen wir natürlich:

Code: Alles auswählen

print repr(int)  #liefert <type 'int'>
print repr(type('Kl',(),{}))  #liefert <class '__main__.Kl'>
Auch Python3-Benutzer werden also beiden Bezeichnungen begegnen.
Leonidas hat geschrieben: Eine (New-Style) Metaklasse erbt von type, an irgendeiner Stelle der MRO.
Das ist eine nützliche Beschreibung, auf die man erst einmal kommen muss, und die ich ebenfalls bis auf weiteres übernehme.
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Goswin hat geschrieben:Ich benutze immer nur Newstyle-Klassen. Trotzdem lesen wir natürlich:

Code: Alles auswählen

print repr(int)  #liefert <type 'int'>
print repr(type('Kl',(),{}))  #liefert <class '__main__.Kl'>
Auch Python3-Benutzer werden also beiden Bezeichnungen begegnen.
Ja, hast recht. Aber generell sind Klassen nichts anderes als selbstdefinierte Datentypen. Dadurch sind Klassen eben erst nützlich, eben dass sie sich so in die Sprache einfügen. Es gibt Sprachen wo es einen Unterschied zwischen primitiven Typen gibt und definierten Klassen, jedoch halte ich das für eine schlechte Idee die zu mehr Verwirrung führt als nötig. Aber selbst dort fungieren Klassen auch als Typen.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
helduel
User
Beiträge: 300
Registriert: Montag 23. Juli 2007, 14:05
Wohnort: Laupheim

Goswin hat geschrieben:(1) Wie unterscheide ich, ob ein Objekt X eine Metaklasse ist oder nicht?
Normalerweise wäre X von type abgeleitet, aber das muss es nicht. Wirklich wichtig ist, dass die "Metaklasse" mit drei Parametern (Name, Basisklassen, Classdict) aufgerufen werden kann. Damit es wenigstens etwas Sinn macht, sollte das zurückgegebene Objekt ebenfalls aufrufbar ("instanzierbar") sein. Wenn das der Fall ist, dann kann man dieses "Ding" ansatzweise wie eine Metaklasse benutzen.

Code: Alles auswählen

def foo(name, bases, attrs):
    def bar():
        return "FOOBAR"
    return bar

class X(object):
    __metaclass__ = foo

X
# <function bar at ...>
x = X()
x
# 'FOOBAR'
Damit es aber sinnvoll wird, sollte die Metaclasse von type erben und natürlich das Metaklassen-Protokoll implementieren. Dann kann man etwas Metamagic betreiben.
(2) Ist das "object", von dem alle anderen Klassen und sogar type erben (siehe type.__mro__), nun eine Metaklasse oder nicht?
Nein. Wenn sie es wäre, dann könnte man "__metaclass__ = object" schreiben. Aber das geht nicht, weil object keine Argumente akzeptiert.

type und object sind sehr speziell. Sie hängen voneinander ab. type ist eine Instanz von sich selbst und gleichzeitig eine Unterklasse von object. object hat keine Superklassen, ist aber eine Instanz von type (das eine Instanz von object ist). Ganz schön kompliziert. Ist aber völlig egal. Das hilft uns nicht wirklich weiter. Fakt ist: type ist eine Metaklasse, da deren Instanzen Klassen sind. object ist eine Instanz von type und dadurch eine Klasse und ist die superste Superklasse, die es in Python gibt :-). (Ich red hier nur von new style classes.)
(3) Erben Metaklassen manchmal ausschließlich von gewöhnlichen Klassen (siehe type.__mro__)?
Ja, siehe type, welches von object erbt. Gut, es erbt auch von sich selbst. Aber schau mal:

Code: Alles auswählen

class NoType(object):
    def __new__(metacls, name, bases, attrs):
        return type(name, bases, attrs)

class X(object):
    __metaclass__ = NoType

X
# <class '__main__.X'>
x = X()
x
# <__main__.X object at 0xb7d9228c>
Metaklassen müssen also nicht von type erben, um irgendwie als Metaklassen zu dienen. Aber wenn du Metaklassen mit all ihren Fähigkeiten nutzen willst, kommst du nicht umhin, von type zu erben. Oder in der "Metaklasse" eine Instanz einer Klasse, die von type erbt, zurückzugeben.

Gruß,
Manuel
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Eine Metaklasse kann jedes beliebige Objekt sein welches 3 Argumente entgegen nimmt. Deswegen gehen auch so lustige Sachen wie:

Code: Alles auswählen

In [1]: def foo(*args):
   ...:     return 'Hello, World!'

In [2]: class Foo(object):
   ...:     __metaclass__ = foo

In [3]: Foo
Out[3]: 'Hello, World!'
Metaklassen sind die mächtigere, seltsamere und komplizierte Alternative zu Dekoratoren.
Benutzeravatar
helduel
User
Beiträge: 300
Registriert: Montag 23. Juli 2007, 14:05
Wohnort: Laupheim

DasIch hat geschrieben:Eine Metaklasse kann jedes beliebige Objekt sein welches 3 Argumente entgegen nimmt. Deswegen gehen auch so lustige Sachen wie:

Code: Alles auswählen

In [1]: def foo(*args):
   ...:     return 'Hello, World!'

In [2]: class Foo(object):
   ...:     __metaclass__ = foo

In [3]: Foo
Out[3]: 'Hello, World!'
Vielleicht noch zur Ergänzung. Das obige Beispiel ist das gleich wie:

Code: Alles auswählen

Foo = foo("Foo", (object,), {})
Da wird einem erst richtig klar, warum Foo plötzlich ein String ist und keine Klasse.

Gruß,
Manuel
Benutzeravatar
Goswin
User
Beiträge: 363
Registriert: Freitag 8. Dezember 2006, 11:47
Wohnort: Ulm-Böfingen
Kontaktdaten:

Was mache ich hier falsch?

Code: Alles auswählen

foobuch = {}
for op in ('__add__','__mul__'):
  def foo(x):
    assert isinstance(x,int)
    return x.op(2)
  foobuch[op[2:-1]+'2'] = foo

print foobuch #alles ok
print foobuch[add_2](5) #FALSCH
print foobuch['add_2'](5) #FALSCH

Code: Alles auswählen

isdifficult('python')==True #*seufz*
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Weil x ein Integer ist und kein Attribut "op" hat. Steht auch in der Fehlermeldung.

Code: Alles auswählen

foobuch = {}
for op in ('__add__','__mul__'):
  def foo(x):
    assert isinstance(x,int)
    return getattr(x, op)(2)
  foobuch[op[2:-1]+'2'] = foo

print foobuch #alles ok
print foobuch[add_2](5) #FALSCH
print foobuch['add_2'](5) #FALSCH
Das Leben ist wie ein Tennisball.
Antworten