2010-02-28 8 views
8

Ayant un arrière-plan en Java, qui est très verbeux et strict, je trouve la possibilité de muter des objets Python pour les donner avec des champs autres que ceux présentés au constructeur vraiment "moche".Construction d'objets Python 3: quel est le plus accepté?

Essayer de m'habituer à une façon de penser Pythonic, Je me demande comment je dois permettre à mes objets d'être construits.

Mon instinct est d'avoir à passer les champs au moment de la construction, tels que:

def __init__(self, foo, bar, baz=None): 
    self.foo = foo 
    self.bar = bar 
    self.baz = baz 

Mais cela peut devenir trop bavard et confus avec de nombreux champs à passer. Pour remédier à cela, je suppose que la meilleure méthode est de passe un dictionnaire au constructeur, dont les champs sont extraits:

def __init__(self, field_map): 
    self.foo = field_map["foo"] 
    self.bar = field_map["bar"] 
    self.baz = field_map["baz"] if baz in field_map else None 

L'autre mécanisme que je peux penser est de ont les champs ajoutés ailleurs, tels que:

class Blah(object): 

    def __init__(self): 
     pass 

... 

blah = Blah() 
blah.foo = var1 

Mais comme cela se sent façon trop lâche pour moi.

(Je suppose que la question dans ma tête est de savoir comment je traite interfaces en Python ...)

Donc, pour réitérer la question suivante: Comment je construire mes objets en Python? Y a-t-il une convention acceptée?

+0

Le temps de construction serait quand '__new__' est appelé. Au moment où '__init__' est appelé, l'instance existe déjà et c'est * l'heure d'initialisation *. – u0b34a0f6ae

+0

@ kaizer.se Vive la terminologie. –

Répondre

9

Le premier que vous décrivez est très commun. Certains utilisent le plus court

class Foo: 
    def __init__(self, foo, bar): 
     self.foo, self.bar = foo, bar 

Votre deuxième approche n'est pas commune, mais une version similaire est la suivante:

class Thing: 
    def __init__(self, **kwargs): 
     self.something = kwargs['something'] 
     #.. 

qui permet de créer des objets comme

t = Thing(something=1) 

Cela peut être plus modifié à

class Thing: 
    def __init__(self, **kwargs): 
     self.__dict__.update(kwargs) 

permettant

t = Thing(a=1, b=2, c=3) 
print t.a, t.b, t.C# prints 1, 2, 3 

Comme Debilski souligne dans les commentaires, la dernière méthode est un peu dangereux, vous pouvez ajouter une liste des paramètres acceptés comme ceci:

class Thing: 
    keywords = 'foo', 'bar', 'snafu', 'fnord' 
    def __init__(self, **kwargs): 
     for kw in self.keywords: 
      setattr(self, kw, kwargs[kw]) 

Il existe de nombreuses variantes, il y a pas de norme commune dont je suis au courant.

+1

Attention: si vous mettez à jour aveuglément votre '.__ dict__', tout le monde peut remplacer toutes vos méthodes et variables d'instance. – Debilski

+0

@Debilski: vous avez absolument un point, car il est facile d'écraser des attributs existants par erreur, mais je voudrais aussi noter qu'en Python, n'importe qui pourrait remplacer vos méthodes et variables de toute façon, s'ils le voulaient. – u0b34a0f6ae

+0

Belle vitrine sur différentes méthodes. –

3

Je n'ai pas vu beaucoup de vos field_map dans la vraie vie. Je pense que cela n'aurait de sens que si vous utilisiez le field_map à un autre endroit de votre code.En ce qui concerne votre troisième exemple: Même si vous n'avez pas besoin de leur assigner (autre que None), il est de pratique courante de déclarer explicitement les attributs dans la méthode __init__, ainsi vous verrez facilement quelles propriétés votre objet a .

Alors ce qui suit est mieux que simplement avoir une méthode __init__ vide (vous obtenez également une plus pylint score pour cela):

class Blah(object): 
    def __init__(self): 
     self.foo = None 
     self.bar = None 

blah = Blah() 
blah.foo = var1 

Le problème avec cette approche est que votre objet pourrait être dans un état non bien défini après l'initialisation, car vous n'avez pas encore défini toutes les propriétés de votre objet. Cela dépend de la logique de votre objet (logique dans le code et dans le sens) et du fonctionnement de votre objet. Si c'est le cas cependant, je vous conseillerais de le faire de cette façon. Si votre objet repose sur foo et bar pour être défini de manière significative, vous devrait vraiment les mettre à l'intérieur de votre __init__ méthode.

Si, toutefois, les propriétés foo et bar ne sont pas obligatoires, vous pouvez les définir par la suite.

Si la lisibilité des listes d'arguments est un problème pour vous: Utilisez des arguments de mots-clés.