2012-06-29 9 views
6

Exkurs startenWas ist falsch an dieser einfachen Python-Metaklasse?

Ich habe gerade erfahren, was metaclasses in Python sind. Ich glaube nicht, dass die Schöpfer von Python wollten, dass jeder sie benutzt. Ich meine, nennen Sie etwas eine Metaklasse, die in den meisten Fällen keine Klasse ist, reicht aus, um die meisten Menschen von diesem Konzept abzubringen!

Exkurs Ende

Auf meine Frage. Ich habe diese einfache Metaklasse geschrieben, um allen Klassen, die im Modul erstellt wurden, eine Standarddokument-Zeichenkette hinzuzufügen. Aber es funktioniert nicht:

def metest(cls,name,bases,dict): 
    cls.setattr(cls,'__doc__',"""Default Doc""") 
    return type(cls,(),{}) 

__metaclass__=metest 

class test(object): 
    pass 

print test.__doc__ 

t=test() 

print t.__doc__ 

Ausgang:

None 
None 

Was mache ich falsch?

Antwort

3

Ich habe Ihr Beispiel Arbeit:

def metest(name, bases, dict): 
    print name, bases, dict 
    dict['__doc__'] = """New Doc""" 
    cls = type(name+"_meta", bases, dict) 
    return cls 

class Test(object): 
    "Old doc" 
    __metaclass__ = metest 

print Test 
print Test.__doc__ 

t = Test() 

print t.__doc__ 
  1. Sprechen Sie die "Meta-Klasse" verwendet.
  2. Korrigieren Sie die Signatur der "Klassenerstellungsfunktion". Die cls wird von uns erstellt.
  3. Haben Sie einen "alten" und einen "neuen" Docstring, um zu unterscheiden.
+0

Es _is_ ist möglich, eine globale Metaklasse zu verwenden, erben Sie einfach nicht von 'object' –

+0

Wer sollte nicht von Objekt erben? Die Metaklasse oder ALLE Klassen im Modul? – ritratt

2

Siehe diese Antwort: Python metaclass and the object base class

Bereitstellung der object Basisklasse der Modulebene metaclass außer Kraft gesetzt und ersetzt sie durch type (die Metaklasse von object).

Darüber hinaus ist Ihre Metaklasse fehlerhaft und funktioniert nicht, selbst wenn Sie es anwenden (indem Sie __metaclass__ innerhalb der Klasse festlegen). Es sollte nur drei Argumente akzeptieren. Normalerweise sehen Sie Beispiele, die vier akzeptieren, aber das liegt daran, dass die Metaklasse normalerweise eine Klasse ist, also akzeptiert sie ein zusätzliches "Selbst" -Argument (das per Konvention cls für Metaklassen heißt).

4

Ich bin nicht ganz vertraut mit der globalen Vorgehensweise, die Sie tun, Einstellung __metaclass__ so. Soweit ich weiß, ist es ein anderer gültiger Stil.

Aber ich werde ein Beispiel für das, was ich bin vertraut mit:

class MeTest(type): 
    def __new__(cls,name,bases,dict): 
     dict['__doc__'] = """Default Doc""" 
     return type.__new__(cls,name,bases,dict) 

class Test(object): 
    __metaclass__ = MeTest 
+0

Ich möchte es mit einer Funktion als Metaklasse tun. – ritratt

1

Möglicherweise ist dies das, was Sie wollen. Vererben von object würde die Metaklasse type machen, so dass Sie das nicht tun, wenn Sie eine globale metaclass

def metest(name, bases, dct): 
    dct['__doc__'] = """Default Doc""" 
    return type(name, bases, dct) 

__metaclass__=metest 

class test: 
    pass 

print test.__doc__ 

t=test() 

print t.__doc__ 
+0

Aber sollte die Metaklasse nicht unbedingt ein Typ sein? Nach allem, was ich verstanden habe, sind alle Klassen in Python Objekte der 'type' Klasse. Wenn ich also alle Klassen ändern möchte, muss ich den "Typ" übersteuern, was "Metaklasse" tut. Also warum sollte ich NICHT von Typ "erben"? Liegt es daran, dass es von der nicht überschriebenen Klasse "type" erbt? Ich bin verwirrt. : S – ritratt

+0

@ritratt, 'metest' ist eine Funktion, die _ eine _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _. Die globale Methode "__metaclass __ = metest" funktioniert nur für klassische Klassen. Sobald Sie von "object" erben, setzen Sie die Metaklasse zurück auf "type", es sei denn, die Klasse überschreibt die Metaklasse erneut –

1

Ihr Modul-Ebene verwenden metaclass außer Kraft gesetzt wird, wie oben erwähnt durch BrenBarn. Um dies zu beheben, versuchen Sie, es zu zu codieren, geben Sie cls zurück, anstatt es als Klasseninstanz festzulegen.

Verwandte Themen