Je vois des modèles comme
def __init__(self, x, y, z):
...
self.x = x
self.y = y
self.z = z
...
assez fréquemment, souvent avec beaucoup plus de paramètres. Existe-t-il un bon moyen d'éviter ce type de répétition fastidieuse? La classe devrait-elle hériter à la namedtuple
place?
__slots__
à cette fin ; c'est légèrement impythonique (plus verbeux pour économiser de la mémoire), mais je l'aime largement pour éviter le risque d'auto-vivifier un tout nouvel attribut si je tape sur le nom.ini <shortcut> x, y, z): <shortcut>
et vous avez terminé.Réponses:
Edit: Si vous avez python 3.7+, utilisez simplement des classes de données
Une solution décoratrice qui garde la signature:
la source
signature
Clause de non-responsabilité: Il semble que plusieurs personnes soient préoccupées par la présentation de cette solution, je vais donc fournir une clause de non-responsabilité très claire. Vous ne devez pas utiliser cette solution. Je ne le donne qu'à titre d'information, vous savez donc que la langue en est capable. Le reste de la réponse montre simplement les capacités linguistiques, et non leur utilisation de cette manière.
Il n'y a vraiment rien de mal à copier explicitement des paramètres dans des attributs. Si vous avez trop de paramètres dans le ctor, cela est parfois considéré comme une odeur de code et vous devriez peut-être regrouper ces paramètres dans moins d'objets. D'autres fois, c'est nécessaire et il n'y a rien de mal à cela. Quoi qu'il en soit, le faire explicitement est la voie à suivre.
Cependant, puisque vous demandez COMMENT cela peut être fait (et non si cela doit être fait), alors une solution est la suivante:
la source
self.__dict__.update(kwargs)
pourrait être légèrement plus pythoniqueA.__init__
s'attendent réellement, et aucune vérification d'erreur pour les noms d'argument mal saisis.kwargs
vous laisse ouvert à l'équivalent d'une attaque par injection SQL. Si votre objet a une méthode nomméemy_method
et que vous passez un argument nommémy_method
au constructeur, alorsupdate()
le dictionnaire, vous venez de remplacer la méthode.Comme d'autres l'ont mentionné, la répétition n'est pas mauvaise, mais dans certains cas, un multiplet nommé peut convenir parfaitement à ce type de problème. Cela évite d'utiliser des locaux () ou des kwargs, qui sont généralement une mauvaise idée.
J'en ai trouvé une utilisation limitée, mais vous pouvez hériter d'un nommé comme avec tout autre objet (suite de l'exemple):
la source
properties
méthode peut être écrite comme justereturn tuple(self)
, ce qui est plus facile à gérer si, à l'avenir, plus de champs sont ajoutés à la définition de namedtuple.XYZ = namedtuple("XYZ", "x y z")
fonctionne tout aussi bien.namedtuple
s dans ce but précis, en particulier dans le code mathématique où une fonction peut être hautement paramétrée et avoir un tas de coefficients qui n'ont de sens qu'ensemble.namedtuple
est qu'ils sont en lecture seule. Vous ne pouvez pas faireabc.x += 1
ou quelque chose comme ça.explicite vaut mieux qu'implicite ... alors vous pouvez le rendre plus concis:
La meilleure question est: devriez-vous?
... cela dit, si vous voulez un tuple nommé, je recommanderais d'utiliser un nommé tuple (rappelez-vous que certaines conditions sont attachées aux tuples) ... peut-être voulez-vous un ordonné ou même juste un dict ...
la source
if k != "self":
pourrait être remplacé parif v is not self:
un test d'identité bon marché, plutôt que par une comparaison de chaînes. Je suppose que techniquement, cela__init__
pourrait être appelé une seconde fois après la construction et être passéself
comme argument ultérieur, mais je ne veux vraiment pas penser à quel genre de monstre ferait cela. :-)locals
:set_fields_from_locals(locals())
. Alors ce n'est plus que les solutions plus magiques basées sur les décorateurs.Pour développer la
gruszczy
réponse, j'ai utilisé un modèle comme:J'aime cette méthode car elle:
super().__init(...)
)X.__init__
Avant Python 3.6, cela ne donne aucun contrôle sur l'ordre dans lequel les attributs sont définis, ce qui pouvait poser un problème si certains attributs sont des propriétés avec des setters qui accèdent à d'autres attributs.
Il pourrait probablement être amélioré un peu, mais je suis le seul utilisateur de mon propre code, donc je ne suis pas inquiet de toute forme d'assainissement des entrées. Un
AttributeError
serait peut-être plus approprié.la source
Vous pouvez également faire:
Bien sûr, vous devrez importer le
inspect
module.la source
C'est une solution sans importation supplémentaire.
Fonction d'assistance
Une petite fonction d'assistance le rend plus pratique et réutilisable:
Application
Vous devez l'appeler avec
locals()
:Tester
Production:
Sans changer
locals()
Si vous n'aimez pas changer,
locals()
utilisez cette version:la source
locals()
ne doit pas être modifié (cela peut affecter l'interpréteur, dans votre cas, la suppressionself
de la portée de la fonction appelante)self
est toujours disponible en__init__
.Une bibliothèque intéressante qui gère cela (et évite beaucoup d'autres passe- partout ) est attrs . Votre exemple, par exemple, pourrait être réduit à ceci (supposons que la classe soit appelée
MyClass
):Vous n'avez même plus besoin d'une
__init__
méthode, à moins qu'elle ne fasse également d'autres choses. Voici une belle introduction de Glyph Lefkowitz .la source
attr
est-elle redondantedataclasses
?Mon 0.02 $. C'est très proche de la réponse de Joran Beasley, mais plus élégant:
De plus, la réponse de Mike Müller (la meilleure à mon goût) peut être réduite avec cette technique:
Et le juste appel
auto_init(locals())
de votre__init__
la source
locals()
ne doit pas être modifié (comportement non défini)C'est une façon naturelle de faire les choses en Python. N'essayez pas d'inventer quelque chose de plus intelligent, cela conduira à un code trop intelligent que personne de votre équipe ne comprendra. Si vous voulez être un joueur d'équipe et continuez à l'écrire de cette façon.
la source
Python 3.7 et versions ultérieures
En Python 3.7, vous pouvez (ab) utiliser le
dataclass
décorateur, disponible depuis ledataclasses
module. De la documentation:Si votre classe est nombreuse et complexe, il peut être inapproprié d'utiliser un fichier
dataclass
. J'écris ceci le jour de la sortie de Python 3.7.0, donc les modèles d'utilisation ne sont pas encore bien établis.la source