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
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.
audax
User
Beiträge: 830
Registriert: Mittwoch 19. Dezember 2007, 10:38

Du rufst mit "x.op(2)' immer die Methode "op" des Objektes "x" mit dem
Parameter 2 auf. Nicht deine Absicht, oder?

So könnte man das machen:
http://paste.pocoo.org/show/112480/
Benutzeravatar
Goswin
User
Beiträge: 363
Registriert: Freitag 8. Dezember 2006, 11:47
Wohnort: Ulm-Böfingen
Kontaktdaten:

Vielen Dank erstmals!

Ich bleibe am Ball und versuche, eure Vorschläge zu verstehen, was allerdings eine Weile dauern wird.

Code: Alles auswählen

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

Vielleicht als kleine Hilfe: Wenn du auf ein Attribut mittels

Code: Alles auswählen

x.attr
zugreifst, dann darfst du dir "attr" nicht als eine Variable vorstellen, denn "attr" ist hier ein Name. Andernfalls könntest du (unbeabsichtigt) sehr seltsame Effekte erzeugen.
Das Leben ist wie ein Tennisball.
Dauerbaustelle
User
Beiträge: 996
Registriert: Mittwoch 9. Januar 2008, 13:48

Zum Thema: Gibt es eine Möglichkeit, dem Interpreter mitzuteilen, er möge doch für jede Operation den Wert aus einer Funktion nehmen? Dann müsste man für solche Sonderklassen nicht jede Operation implementieren.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Klar: "__getattr__", bzw. "__getattribute__" oder mittels Vererbung und natürlich Metaklassen.
Das Leben ist wie ein Tennisball.
Benutzeravatar
str1442
User
Beiträge: 520
Registriert: Samstag 31. Mai 2008, 21:13

Sofern die Funktionen entsprechend kompatibel sind, kannst du auch im Namensraum der Klasse jeder gewünschten "magic method" mittels einfacher Zuweisung die Funktion zuteilen. Das erste Attribut wird dann als "self" interpretiert. Funktioniert natürlich nicht bei zb Funktionen aus dem Operator Modul, aber es kommt natürlich auf deine Funktion (oder eine entsprechende Methode der Klasse) an.
Dauerbaustelle
User
Beiträge: 996
Registriert: Mittwoch 9. Januar 2008, 13:48

EyDu hat geschrieben:Klar: "__getattr__", bzw. "__getattribute__" oder mittels Vererbung und natürlich Metaklassen.
Wie soll das aussehen?
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Hier im Forum und über Google lassen sich dutzende Beispiele finden.
Das Leben ist wie ein Tennisball.
Antworten