Seite 2 von 2

Verfasst: Dienstag 28. April 2009, 09:50
von Goswin
jerch hat geschrieben:Fraglich ist noch, ob das Verhalten nur für direkte Typnachfolger von Metaklassen oder für Klassentypen generell gilt.
...
Habs mal kurz getestet, scheint tatsächlich generell für Klassentypen zu gelten.
EyDu hat geschrieben:Hier wird gar nichts unterschiedlich behandelt. Erst werden die Attribute im Objekt gesucht, dann in den Klassen entsprechend der Vererbungshierarchie.

Ich würde jetzt im Nachhinein auch sagen, das Verhalten gilt ganz allgemein, und je länger ich darüber nachdenke, desto logischer kommt es mir vor. Ein ganz einfaches Beispiel (ohne Metaklassen) wäre:

Code: Alles auswählen

class K(object):
  foo = lambda oK,verwirf: "Klassenfunktion"
#
oK = K()
oK.foo = lambda verwirf: "Objektfunktion"


#"Objektsuche VOR Klassensuche:
print oK.foo(None)  #druckt "Objektfunktion" aus
Da Klassen selber "nur" von Metaklassen erzeugte Objekte sind, gilt parallel zum obigen Beispiel auch das Beispiel:

Code: Alles auswählen

class mK(type):
  foo = lambda K,verwirf: "Klassenfunktion"
#
class K(object):
  __metaclass__ = mK
  foo = lambda verwirf: "Objektfunktion"
#
oK = K()


#"Objektsuche VOR Klassensuche:
print K.foo(oK)  #druckt "Objektfunktion" aus
Das einzige, was zu beachten ist, ist dass Klassenaufrufen (gleich welcher Art) immer eine Instanz der Klasse hinzuzufügen ist.

Verfasst: Dienstag 28. April 2009, 10:48
von EyDu
Vielleicht hilft euch das bei euren Spekulationen auf die Sprünge:

Code: Alles auswählen

>>> class Meta(type):
...     pass
...
>>> class Spam(object):
...     __metaclass__ = Meta
...
>>> s = Spam()
>>> type(s)
<class '__main__.Spam'>
>>> type(Spam)
<class '__main__.Meta'>
>>> isinstance(s, Spam)
True
>>> isinstance(s, Meta)
False

Verfasst: Dienstag 28. April 2009, 17:17
von jerch
@EyDu:
Naja, das war schon klar.

Der Hund liegt trotzdem in der Typenhierarchie begraben, für Klassen findet Python das Metaklassenattribut via type(Klasse).__dict__, für Objekte dagegen nicht (das Metaklassenattribut wäre erst mit type(type(obj)) zu finden).
In meinen Augen ist das schon ein Unterschied in der Behandlung, zumal die Dokumentation die Metaklassen explizit rausnimmt (allerdings wird auch nur von objects geredet). Ob dieser Unterschied nun hard kodiert ist oder strukturell bedingt ist, ist für mich als Anwender der Sprache egal, da die Phänomenologie entscheidend ist.

Verfasst: Dienstag 28. April 2009, 18:09
von b.esser-wisser
Welcher Hund denn nun wieder?
Attribute werden in
a) Instanzen
b) Klassen
c) Eltern-klassen
gesucht:

Code: Alles auswählen

# Beispiel zur Verwirrung
class Meta(type):
    obscure_attr = "In Meta"
class Foo(object):
    foo_attr = "In Foo"
class Bar(Foo):
    bar_attr = "In Bar"
class Bar2(object):
    bar_attr = "In Bar2"
class Baz(Bar, Bar2):
    __metaclass__ = Meta
    baz_attr = "In Baz"
    def __init__(self):
        self.inst_attr="In baz-instance"
a_single_instance = Baz()
#geht:
print a_single_instance.inst_attr #logisch
print a_single_instance.baz_attr
print a_single_instance.foo_attr
#geht nicht:
try:
    print a_single_instance.obscure_attr
except AttributeError, ex:
    print ex.message
#geht:
print Baz.obscure_attr
# DENN: Baz IST eine Instanz von Meta()!
print isinstance(Baz, Meta)
hth, Jörg

Verfasst: Dienstag 28. April 2009, 18:31
von Darii
jerch hat geschrieben:Der Hund liegt trotzdem in der Typenhierarchie begraben,
Ja natürlich liegt das an der Typhierarchie. Das sich zwei Objekte die unterschiedliche Attribute/Typen/etc. haben sich unterschiedlich verhalten sollte eigentlich niemanden Verwundern. Und du solltest auch nicht zwischen Objekten und Klassen unterscheiden sondern lieber zwischen Instanzen und Klassen, Objekte sind nämlich beide.

Verfasst: Dienstag 28. April 2009, 21:23
von EyDu
Und? Da ist immer noch nichts magisches.

Ich mach es mal noch ein wenig einfacher:

Code: Alles auswählen

>>> class Meta(type):
	pass

>>> class Spam(object):
	__metaclass__ = Meta

	
>>> Spam.__base__
<type 'object'>
Metaklasen kommen nicht in der Klassenhierarchie vor.