Le Zen de Python il ya des états qui ne devrait être qu'un moyen de faire des choses - mais souvent je tombe sur le problème de la détermination de l'utilisation d'une fonction par rapport au cas d'utilisation d'une méthode.
Prenons un exemple trivial - un Échiquier de l'objet. Disons que nous avons besoin d'un moyen d'obtenir le Roi se déplace sur le plateau. Avons-nous écrire Échiquier.get_king_moves() ou get_king_moves(chess_board)?
Voici quelques questions que j'ai regardé:
- Pourquoi python utilisation magiques "méthodes"?
- Est-il un motif Python chaînes n'ont pas une longueur de chaîne de la méthode?
Les réponses j'ai été peu concluantes:
Pourquoi Python utiliser des méthodes pour certaines fonctionnalités (par exemple, liste.index ()), mais des fonctions pour d'autres (par exemple, len(liste))?
La raison majeure est de l'histoire. Les fonctions ont été utilisées pour ces opérations, qui ont été générique pour un groupe de types et qui ont été destiné à travailler, même pour des objets qui n'ont pas du tout les méthodes de (par exemple des n-uplets). Il est aussi pratique d'avoir une fonction qui peut être facilement appliqué à un amorphe collection d'objets lorsque vous utilisez les caractéristiques fonctionnelles de Python (map(), appliquer() et al).
En fait, la mise en œuvre de len(), max(), min() comme une fonction intégrée est en fait moins de code que de les mettre en œuvre que les méthodes pour chaque type. On peut ergoter sur des cas individuels, mais c'est une partie de Python, et il est trop tard pour faire des changements fondamentaux tels maintenant. Les fonctions ont pour rester à éviter massive du code de la rupture.
Bien qu'intéressante, le ci-dessus ne veut pas vraiment dire grand-chose de ce que la stratégie à adopter.
C'est l'une des raisons - avec des méthodes personnalisées, les développeurs seraient libre de choisir un autre nom de la méthode, comme getLength(), longueur(), getlength() ou que ce soit. Python applique une stricte de nommage, de sorte que le commun de la fonction len() peut être utilisée.
Un peu plus intéressant. De mon point de vue est que les fonctions sont, en un sens, la Pythonic version d'interfaces.
Enfin, à partir de Guido lui-même:
Parler des Capacités/Interfaces m'a fait penser à certaines de nos "rogue" spécial noms de méthode. Dans la Langue de Référence, dit-il, "Un la classe peut mettre en œuvre de certaines opérations qui sont invoqués par des syntaxe (telles que des opérations arithmétiques ou subscripting et de tranchage) par la définition de méthodes ayant des noms spéciaux." Mais il y a toutes ces méthodes avec des noms spéciaux comme
__len__
ou__unicode__
qui semblent être prévu pour le bénéfice de fonctions intégrées, plutôt que pour le soutien de la syntaxe. Sans doute dans une interface en Python, ces méthodes serait à son tour tenu régulièrement nommé les méthodes à l'ABC, de sorte que__len__
deviendraitclass container: ... def len(self): raise NotImplemented
Quoique, en y réfléchissant un peu plus, je ne vois pas pourquoi tous les syntaxiques les opérations ne serait pas juste appeler approprié normalement méthode nommée sur un ABC. "
<
", par exemple, aurait sans doute invoquer "object.lessthan
" (ou peut-être "comparable.lessthan
"). Donc, une autre avantage serait la possibilité de se sevrer de Python à l'écart de ce mutilé-nom de la singularité, ce qui me semble un HCI amélioration.Hm. Je ne suis pas sûr que je suis d'accord (figure :-).
Il y a deux bits de "Python justification" que j'aimerais vous expliquer d'abord.
Tout d'abord, j'ai choisi len(x) sur x.len() pour HCI raisons (
def __len__()
sont venus beaucoup plus tard). Il y a deux entrelacés raisons en fait, les deux HCI:(a) Pour certaines opérations, le préfixe de la notation juste se lit mieux que postfix -- prefix (et infix!) les opérations ont une longue tradition dans les mathématiques, qui aime les notations, où les images, d'aider à la mathématicien de penser à un problème. Comparer la facilité avec laquelle nous réécriture d'une formule comme
x*(a+b)
enx*a + x*b
à la maladresse de faire la même chose à l'aide d'un raw OO notation.(b) Quand j'ai lu le code qui, dit -
len(x)
je sais que c'est de demander de la longueur de quelque chose. Cela me dit deux choses: le résultat est un entier, et l'argument est une sorte de conteneur. Au contraire, quand j'ai lux.len()
, je sais déjà qu'x
est une sorte de conteneur mise en œuvre d'une interface ou d'hériter d'une classe qui a une normelen()
. Témoin de la confusion, nous ont de temps en temps quand une classe qui n'est pas mise en œuvre d'une cartographie a unget()
oukeys()
méthode, ou quelque chose qui n'est pas un fichier a unwrite()
méthode.Dire la même chose d'une autre manière, je vois 'len' tel que construit le fonctionnement. Je déteste perdre. Je ne peux pas dire à coup sûr si vous avez voulu ou pas, mais 'def len(self): ...' ressemble à vous souhaitez rétrograder à une méthode ordinaire. Je suis fortement -1 sur que.
Le deuxième bit de Python justification, j'ai promis à expliquer, c'est la raison pourquoi j'ai choisi une méthode spéciale pour look
__special__
et non pas simplementspecial
. Je m'attendais à beaucoup d'opérations que les classes pourrait vouloir pour remplacer, un certain niveau (par exemple,__add__
ou__getitem__
), d'autres non donc standard (par exemple, les achards de l'__reduce__
pour un long temps n'avait pas de soutien dans C le code). Je n'en veux pas à ces opérations spéciales pour une utilisation ordinaire les noms de méthode, parce que les pré-existants des classes ou des classes écrit par les utilisateurs sans encyclopédique de la mémoire pour toutes les méthodes spéciales, serait de nature à accidentelle de définir des opérations qu'ils ne signifie pas pour mettre en œuvre, éventuellement avec des conséquences désastreuses. Ivan Krstić explique cette plus concis dans son message, qui est arrivé après que j'ai écrit tout cela.-- --Guido van Rossum (page d'accueil: http://www.python.org/~guido/)
Ma compréhension de cette est que, dans certains cas, le préfixe de notation tout simplement plus de sens (c'est à dire, le Canard.quack plus de sens que quack(de Canard) à partir d'un point de vue linguistique.) et encore une fois, les fonctions de permettre des "interfaces".
Dans un tel cas, mon estimation serait de mettre en place get_king_moves basée uniquement sur Guido, premier point. Mais cela laisse encore beaucoup de questions ouvertes relatives à dire, la mise en œuvre d'une pile et file d'attente de la classe avec les mêmes méthodes push et pop - ils doivent être des fonctions ou des méthodes? (ici, je suppose que les fonctions, parce que je veux vraiment être le signal d'un push-pop de l'interface)
TLDR: quelqu'un Peut m'expliquer ce que la stratégie pour décider quand utiliser les fonctions de vs méthodes devraient être?