Je suis un développeur Java qui a joué avec Python par intermittence. Je suis récemment tombé sur cet article qui mentionne les erreurs courantes commises par les programmeurs Java lorsqu'ils adoptent Python. La première a attiré mon attention :
Une méthode statique en Java ne se traduit pas par une méthode de classe en Python. Bien sûr, il en résulte plus ou moins le même effet, mais le but d'une classmethod est en fait de faire quelque chose qui n'est généralement même pas possible en Java (comme hériter d'un constructeur qui n'est pas par défaut). La traduction idiomatique d'une méthode statique Java est généralement une fonction au niveau du module, et non une classmethod ou staticmethod. (Et les champs statiques finaux devraient se traduire par des constantes au niveau du module).
Ce n'est pas vraiment un problème de performance, mais un programmeur Python qui doit travailler avec du code Java-idiom comme celui-ci sera plutôt irrité par le fait de taper Foo.Foo.someMethod alors qu'il devrait simplement s'agir de Foo.someFunction. Mais notez que l'appel à une classmethod implique une allocation de mémoire supplémentaire que l'appel à une staticmethod ou à une function n'implique pas.
Oh, et toutes ces chaînes d'attributs Foo.Bar.Baz ne sont pas gratuites non plus. En Java, ces noms en pointillés sont recherchés par le compilateur, de sorte qu'au moment de l'exécution, leur nombre n'a pas vraiment d'importance. En Python, les recherches se font au moment de l'exécution, donc chaque point compte. (Rappelez-vous qu'en Python, "Flat is better than nested", bien que cela soit plus lié à "Readability counts" et "Simple is better than complex" qu'à la performance).
J'ai trouvé cela un peu étrange car la documentation de méthode statique dice:
Les méthodes statiques en Python sont similaires à celles que l'on trouve en Java ou en C++. Voir également classmethod() pour une variante utile pour créer des constructeurs de classe alternatifs.
Ce qui est encore plus surprenant, c'est que ce code :
class A:
def foo(x):
print(x)
A.foo(5)
échoue comme prévu dans Python 2.7.3 mais fonctionne correctement dans 3.2.3 (bien que vous ne puissiez pas appeler la méthode sur une instance de A, seulement sur la classe).
Il y a donc trois façons d'implémenter les méthodes statiques (quatre si l'on compte l'utilisation de classmethod), chacune avec des différences subtiles, l'une d'entre elles n'étant apparemment pas documentée. Cela semble en contradiction avec le mantra de Python, à savoir Il devrait y avoir une - et de préférence une seule - façon évidente de le faire. Quel est l'idiome le plus pythonique ? Quels sont les avantages et les inconvénients de chacun ?
Voici ce que j'ai compris jusqu'à présent :
Fonction du module :
- Evite le problème Foo.Foo.f()
- Pollue l'espace de noms du module plus que les autres solutions.
- Pas d'héritage
méthode statique :
- Maintient les fonctions liées à la classe à l'intérieur de la classe et en dehors de l'espace de noms du module.
- Permet d'appeler la fonction sur des instances de la classe.
- Les sous-classes peuvent surcharger la méthode.
méthode de classe :
- Identique à staticmethod, mais transmet également la classe comme premier argument.
Méthode régulière (Python 3 uniquement) :
- Identique à staticmethod, mais on ne peut pas appeler la méthode sur les instances de la classe.
Est-ce que je réfléchis trop ? S'agit-il d'un problème sans importance ? Merci de m'aider !