2010-03-23 10 views
5

Ecco il mio problema. Voglio che la seguente classe abbia un sacco di attributi di proprietà. Potrei scriverli tutti come foo e bar o in base ad altri esempi che ho visto, sembra che potrei usare un decoratore di classe, una metaclasse, o sovrascrivere il metodo __new__ per impostare le proprietà automaticamente. Non sono sicuro di quale sarebbe il modo "giusto" di farlo.Devo usare una metaclasse, un decoratore di classe, o sovrascrivere il metodo __new__?

class Test(object): 
    def calculate_attr(self, attr): 
     # do calculaty stuff 
     return attr 

    @property 
    def foo(self): 
     return self.calculate_attr('foo') 

    @property 
    def bar(self): 
     return self.calculate_attr('bar') 
+2

In caso di dubbio, sempre andare con semplice ed evidente. Se * tu * non riesci a capirlo facilmente, nemmeno i manichini (come me) a cui verrà chiesto di mantenere il tuo codice. –

+0

Quando cambi la natura delle tue domande, di solito è meglio solo aprirne una nuova. –

risposta

4

La magia è male. Rende il tuo codice più difficile da capire e da mantenere. Non hai praticamente mai bisogno di metaclassi o __new__.

Sembra che il tuo caso d'uso potrebbe essere attuato con il codice abbastanza semplice (con solo un piccolo accenno di magia):

class Test(object): 
    def calculate_attr(self, attr): 
     return something 

    def __getattr__(self, name): 
     return self.calculate_attr(name) 
+1

@ Non hai praticamente mai bisogno di metaclassi o '__new__': sono fortemente in disaccordo. Nella mia azienda avevamo già due occasioni, quando avevamo buone motivazioni per l'utilizzo di metaclassi. Il primo era la creazione di un livello di astrazione per un database personalizzato che avevamo usato e l'altro stava creando il nostro sistema Model per ldap. Non riesco davvero a capire, da dove viene questo risentimento per i metaclassi. È un concetto facile da afferrare e davvero utile in determinate situazioni. – gruszczy

+1

@gruszczy, le metaclassi non sono difficili da capire, in realtà sono un'idea abbastanza semplice, anche se la sintassi e l'uso di Python fanno sì che alcune persone abbiano problemi. Tuttavia, sono soggetti a errori a causa del modo in cui si propagano e talvolta sono difficili da combinare: non è automaticamente possibile che una classe utilizzi due metaclassi nella sua costruzione, anche se si tratta di un'operazione perfettamente ragionevole. Questo problema è esacerbato dal fatto che le metaclassi spesso non sono esposte come parte dell'API pubblica di un sistema. –

2

di __new__ Una metaclasse non diventa il __new__ per la classe fai-è usato per fare la classe stessa. L'oggetto classe attuale viene restituito dal metaclass. Una nuova istanza di una classe viene restituita da __new__.

Si consideri il seguente codice (folle):.

def MyMetaClass(name, bases, dict): 
    print "name", name 
    print "bases", bases 
    print "dict", dict 
    return 7 

class C('hello', 'world'): 
    __metaclass__ = MyMetaClass 

    foo = "bar" 

    def baz(self, qux): 
     pass 

print "C", C 

(io ho usato una funzione invece di una classe come la metaclasse Qualsiasi callable può essere usato come un metaclasse, ma molte persone scelgono di destra loro come classi che ereditano da type nuovi overrided. Le differenze tra che una funzione sono sottili.)

Produce

name C 
bases ('hello', 'world') 
dict {'baz': <function baz at 0x4034c844>, '__module__': '__main__', 'foo': 'bar', '__metaclass__': <function MyMetaClass at 0x40345c34>} 
C 7 

Questo ti aiuta a capire meglio quali metaclassi sono?

molto raramente è necessario definire un metaclasse di tua scelta.

+0

Non dovrebbe essere "oggetto di classe reale" piuttosto che "oggetto di classe effettivamente"? –

1

Metaclass viene utilizzato quando viene creata una nuova classe, non un'istanza. In questo modo è possibile ad esempio registrare le classi (django lo fa e lo usa ad esempio per creare tabelle nel database). Dal class è un'istruzione a cui puoi pensare come decoratore di una classe.