Pourquoi avez-vous besoin de «soi»? en Python pour faire référence aux variables d'instance?

13

J'ai programmé dans un certain nombre de langages comme Java, Ruby, Haskell et Python. Je dois basculer entre plusieurs langues par jour en raison des différents projets sur lesquels je travaille. Maintenant, le problème est que j'oublie souvent d'écrire selfcar le premier paramètre dans les définitions de fonction en Python est le même que pour les méthodes d'appel sur le même objet.

Cela dit, je suis assez étonné par cette approche de Python. Fondamentalement, nous devons taper plus pour faire avancer les choses, dans les langages comme Java et Ruby, les choses sont simplifiées en référençant automatiquement les variables dans l'objet actuel.

Ma question est pourquoi est-ce selfnécessaire? Est-ce purement un choix de style, ou y a-t-il une raison pour laquelle Python ne peut pas vous laisser omettre selfla façon dont Java et C ++ vous laissent omettre this?

vivek
la source
1
@gnat n'est plus que des pros, et sérieusement c'est une bonne question qui me dérange depuis quelques jours, ne le tuez pas en votant.
vivek
2
Cette question a été plus que complètement couverte par stackoverflow.com/questions/2709821/… .
David Arno
Ma compréhension est qu'il est basé sur le style C de passer un pointeur vers une structure comme premier argument.
Dannnno
Écriture @staticmethodavant la déclaration de méthode, supprime l'erreur (juste pour info et également déconseillée)
Yash

Réponses:

23

1) Pourquoi est-il selfrequis comme paramètre explicite dans les signatures de méthode?

Parce que les méthodes sont des fonctions et ne foo.bar(baz)sont que du sucre syntaxique pour bar(foo, baz). Les classes ne sont que des dictionnaires dont certaines valeurs sont des fonctions. (Les constructeurs ne sont également que des fonctions, c'est pourquoi Python n'a pas besoin new). Vous pouvez dire que Python rend explicite que les objets sont construits à partir de composants plus simples. Ceci est conforme à la philosophie "explicite vaut mieux qu'implicite".

En revanche, en Java, les objets sont vraiment magiques et ne peuvent pas être réduits à des composants plus simples dans le langage. En Java (au moins jusqu'à Java 8), une fonction est toujours une méthode appartenant à un objet, et cette propriété ne peut pas être modifiée en raison de la nature statique du langage. Par conséquent, il n'y a aucune ambiguïté quant à ce qui thisfait référence, il est donc logique de le définir implicitement.

JavaScript est un exemple de langage qui a un implicite thiscomme Java, mais où les fonctions peuvent exister séparément des objets comme en Python. Cela conduit à beaucoup de confusion sur ce à quoi se thisréfère lorsque les fonctions sont transmises et appelées dans différents contextes. Beaucoup pensent instinctivement thisdoivent se référer à une propriété intrinsèque de la fonction, alors qu'elle est en fait purement déterminée par la façon dont la fonction est appelée. Je crois qu'avoir thisun paramètre explicite comme en Python rendrait cela beaucoup moins déroutant.

Quelques autres avantages du selfparamètre explicite :

  • Les décorateurs ne sont que des fonctions qui enveloppent d'autres fonctions. Puisque les méthodes ne sont que des fonctions, les décorateurs fonctionnent tout aussi bien sur les méthodes. S'il y avait une sorte de soi implicite, les décorateurs ne travailleraient pas de manière transparente sur les méthodes.

  • Les méthodes de classe et les méthodes statiques ne prennent pas de paramètre d'instance. Les méthodes de classe prennent une classe comme premier argument (généralement appelé cls). L'explicite selfou les clsparamètres rendent beaucoup plus clair ce qui se passe et ce à quoi vous avez accès dans la méthode.

2) Pourquoi les variables d'instances doivent-elles toujours être qualifiées par " self.?

En Java, vous n'avez pas besoin de préfixer les variables membres avec " this.", mais en Python " self." est toujours requis. La raison en est que Python n'a pas de syntaxe explicite pour déclarer des variables, il n'y aurait donc aucun moyen de savoir si x = 7est censé déclarer une nouvelle variable locale ou l'affecter à une variable membre. La spécification self.résout cette ambiguïté.

JacquesB
la source
La référence implicite de variable membre (sans self., comme Java) est fondamentalement incompatible avec les règles de portée et lorsque vous devez y être explicite, être implicite sur le paramètre n'a plus beaucoup de sens.
Jan Hudec
@JanHudec: Bien, point. Je l'ai ajouté à la réponse.
JacquesB
6

Il y a une raison assez simple pour laquelle AFAIK n'a pas vraiment été abordé dans le double intersite, ni ici: Python a commencé comme un langage procédural. Il était basé sur ABC, également un langage procédural.

L'Orientation-Orientation a été ajoutée plus tard, et quand elle a été ajoutée, Guido van Rossum a voulu ajouter le minimum de fonctionnalités possibles, afin de garder la conception de Python simple. Python avait déjà des dicts et des fonctions, alors pourquoi ajouter quelque chose de complètement nouveau au langage, quand un objet peut simplement être un dictde slots et une classe peut être simplement une dictde fonctions? Une méthode peut être interprétée comme une fonction partiellement appliquée qui se ferme sur un seul argument distinctif. Et c'est précisément ainsi que les méthodes sont implémentées en Python: elles ne le sont pas. Ce ne sont que des fonctions qui reçoivent un argument distinctif supplémentaire.

Jörg W Mittag
la source
Je crois que Python supportait OO et avait des classes et l'héritage de la toute première version publiée. C'est du moins ce que me dit Wikipédia. Mais le processus de van Rossums dans la conception initiale du langage aurait pu être tel que vous le décrivez.
JacquesB
Merci pour le lien, c'est une lecture vraiment intéressante.
JacquesB
2

Voici mes conclusions basées sur les réponses ci-dessus et en lisant la propre randonnée de Guido sur ce sujet:

La grande idée

Les fonctions sont les blocs de construction importants en Python (ou nous devrions dire le seul), en fait, nous émulons en quelque sorte la POO en utilisant des fonctions.

Étant donné qu'une classe n'est rien d'autre qu'un dictionnaire de fonctions, nous pouvons attacher n'importe quelle fonction à n'importe quelle classe au moment de l'exécution. Fondamentalement, c'est à cause de ce besoin de lancer les fonctions au moment de l'exécution que nous pouvons faire des trucs comme Monkey Patching . Voici le selfparamètre supportant le polymorphisme paramétrique.

vivek
la source
1
Les questions à réponse automatique sont encouragées lorsque votre réponse est une réponse de haute qualité. Lorsque je compare votre réponse ici aux autres réponses, je me demande pourquoi vous avez ressenti le besoin d'ajouter ceci. Les autres réponses vont plus en profondeur et ajoutent plus de détails que ce que fait votre réponse.
1
@ GlenH7 la réponse était juste pour ma référence parce que chaque fois que je ne peux pas venir lire la réponse de tout le monde encore et encore. En ce qui concerne la qualité, dites-moi si des informations sont trompeuses. Quoi qu'il en soit, j'attends généralement 2-3 jours pour accepter une réponse.
vivek
Le vote à la baisse devient une monnaie bon marché et tout le monde ici le dépense des deux mains sans en connaître la signification. Vous rendez-vous compte que si quelqu'un vient ici, voir cette réponse rejetée supposerait que c'est faux!
vivek