Modifier : Si vous avez python 3.7+, utilisez simplement classes de données
Une solution décorative qui conserve la signature :
import decorator
import inspect
import sys
@decorator.decorator
def simple_init(func, self, *args, **kws):
"""
@simple_init
def __init__(self,a,b,...,z)
dosomething()
behaves like
def __init__(self,a,b,...,z)
self.a = a
self.b = b
...
self.z = z
dosomething()
"""
#init_argumentnames_without_self = ['a','b',...,'z']
if sys.version_info.major == 2:
init_argumentnames_without_self = inspect.getargspec(func).args[1:]
else:
init_argumentnames_without_self = tuple(inspect.signature(func).parameters.keys())[1:]
positional_values = args
keyword_values_in_correct_order = tuple(kws[key] for key in init_argumentnames_without_self if key in kws)
attribute_values = positional_values + keyword_values_in_correct_order
for attribute_name,attribute_value in zip(init_argumentnames_without_self,attribute_values):
setattr(self,attribute_name,attribute_value)
# call the original __init__
func(self, *args, **kws)
class Test():
@simple_init
def __init__(self,a,b,c,d=4):
print(self.a,self.b,self.c,self.d)
#prints 1 3 2 4
t = Test(1,c=2,b=3)
#keeps signature
#prints ['self', 'a', 'b', 'c', 'd']
if sys.version_info.major == 2:
print(inspect.getargspec(Test.__init__).args)
else:
print(inspect.signature(Test.__init__))
31 votes
La réceptivité n'est pas toujours mauvaise. Gardez à l'esprit que le modèle de classe de Python n'inclut pas de définition explicite des attributs d'instance, donc ces affectations sont les équivalents auto-documentés.
4 votes
@chepner : Eh bien, n'est-ce pas exiger définition explicite. Vous pouvez utiliser
__slots__
pour l'objectif cependant C'est légèrement impythique (plus verbeux pour économiser de la mémoire), mais je l'aime surtout pour éviter le risque d'auto-vivifier un tout nouvel attribut si je fais une faute de frappe dans le nom.2 votes
Tout bon éditeur aura des modèles. Vous tapez
ini <shortcut> x, y, z): <shortcut>
et vous avez terminé.3 votes
Les Namedtuples sont géniaux, si vous voulez un objet de valeur immuable. Si vous voulez une classe ordinaire et mutable, vous ne pouvez pas les utiliser.
4 votes
"Ne pas" est une bonne option, toute option disponible tuera la signature de la méthode (et donc potentiellement toute l'interface). Par ailleurs, si vos classes ont une quantité insupportable de champs à initialiser, vous pourriez envisager de les scinder.
0 votes
@RemcoGerlich une classe dérivée de
namedtuple
peuvent avoir des attributs mutables (en plus des attributs immuables hérités).0 votes
N'oubliez pas que ce modèle vous permet également de définir des valeurs par défaut pour x/y/z. Les alternatives ne le font pas. De plus, ce n'est fastidieux que si cela représente une part importante du travail. Je travaille dans ce secteur depuis 20 ans, et je n'ai encore jamais vu un constructeur où la copie des paramètres représentait une part importante du fichier entier !
0 votes
@Kroltan J'aimerais voir votre commentaire comme une réponse.
1 votes
@JackStout Ce ne serait pas une réponse appropriée. Il demande une comment le faire pas devrais-je le faire .
0 votes
Pour le PO : il serait utile que vous expliquiez pourquoi vous voulez éviter cela ?
0 votes
Plutôt que d'être un modèle commun, les méthodes init ne font souvent que commencer avec ce modèle. Au fur et à mesure que vous travaillerez avec lui, vous aurez certainement besoin de faire de la logique supplémentaire avec au moins certains args, et donc avec une approche de réglage automatique, vous devrez maintenant faire le traitement des propriétés self.<name> que vous venez de régler, de sorte que le code init global semble plus compliqué que l'alternative.