2010-03-23 14 views
5

Voici mon problème. Je veux que la classe suivante ait un tas d'attributs de propriété. Je pourrais les écrire tous comme foo et bar, ou basé sur d'autres exemples que j'ai vus, il me semble que je pourrais utiliser un décorateur de classe, une métaclasse, ou remplacer la méthode __new__ pour définir les propriétés automatiquement. Je ne suis pas sûr de ce que la «bonne» façon de faire serait.Devrais-je utiliser une métaclasse, un décorateur de classe ou remplacer la méthode __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

En cas de doute, allez toujours simple et évidente. Si * vous * n'arrivez pas à le comprendre facilement, vous ne pouvez pas non plus demander aux mannequins (comme moi) de maintenir votre code. –

+0

Lorsque vous changez la nature de vos questions, il est généralement préférable d'en ouvrir une nouvelle. –

Répondre

4

La magie est mauvaise. Cela rend votre code plus difficile à comprendre et à maintenir. Vous n'avez pratiquement jamais besoin de métaclasses ou de __new__.

Il ressemble à votre cas d'utilisation pourrait être mise en œuvre avec le code assez simple (avec seulement un petit soupçon de magie):

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

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

@ Vous n'avez pratiquement jamais besoin de métaclasses ou de '__new__': je ne suis pas du tout d'accord. Dans mon entreprise, nous avions déjà deux occasions, lorsque nous avions une bonne motivation pour utiliser des métaclasses. La première était de créer une couche d'abstraction pour une base de données personnalisée que nous avions utilisée et l'autre créait notre propre système de modèle pour ldap. Je ne peux pas vraiment comprendre, d'où vient ce ressentiment pour les métaclasses. C'est un concept facile à saisir et vraiment utile dans certaines situations. – gruszczy

+1

@gruszczy, les métaclasses ne sont pas difficiles à comprendre, elles sont en fait une idée assez facile, bien que la syntaxe et l'utilisation pour eux en Python rendent certaines personnes difficiles. Ils sont cependant sujets aux erreurs en raison de la façon dont ils se propagent et parfois difficiles à combiner - il n'est pas automatiquement possible d'avoir une classe qui utilise deux métaclasses dans sa construction même si c'est une opération parfaitement raisonnable. Ce problème est exacerbé par le fait que les métaclasses ne sont souvent pas exposées dans le cadre de l'API publique d'un système. –

2

__new__ est une métaclasse ne devient pas le __new__ pour la classe que vous faites-il est utilisé pour faire la classe elle-même. L'objet de classe réel est renvoyé par la métaclasse. Une nouvelle instance d'une classe est renvoyée par __new__.

Considérez ce qui suit (fou) Code:.

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 

(j'ai utilisé une fonction au lieu d'une classe comme métaclasse Tout appelable peut être utilisé comme métaclasse, mais beaucoup de gens choisissent de droite leur en tant que classes héritant de type avec de nouveaux overrided. Les différences entre qu'une fonction est subtile.)

Il produit

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

Est-ce que cela vous aide à mieux comprendre les métaclasses ?

Vous aurez très rarement besoin de définir une métaclasse de votre choix.

+0

Cela ne devrait-il pas être "objet de classe réel" plutôt que "objet de classe"? –

1

La métaclasse est utilisée lorsqu'une nouvelle classe - et non une instance - est créée. De cette façon, vous pouvez par exemple enregistrer des classes (django le fait et l'utilise par exemple pour créer des tables dans la base de données). Depuis class est une instruction que vous pouvez considérer comme un décorateur pour une classe.