web-dev-qa-db-fra.com

Pourquoi python utilise deux traits de soulignement pour certaines choses?

Je suis assez nouveau dans les langages de programmation actuels, et Python est mon premier. Je connais un peu Linux, assez pour obtenir un emploi d'été avec (je suis toujours en haut école), et au travail, j'ai beaucoup de temps libre que j'utilise pour apprendre Python.

Une chose m'attire cependant. Qu'est-ce qui est exactement différent dans Python lorsque vous avez des expressions telles que

x.__add__(y) <==> x+y
x.__getattribute__('foo') <==> x.foo

Je sais ce que font les méthodes et les trucs, et j'obtiens ce qu'ils font, mais ma question est la suivante: en quoi ces méthodes de double soulignement ci-dessus sont-elles différentes de leurs équivalents plus simples?

P.S., cela ne me dérange pas d'être enseigné sur l'histoire de la programmation, en fait, je trouve très utile de savoir :) Si ce sont principalement des aspects historiques de Python, n'hésitez pas à commencer à vous promener.

51
Andrew

Eh bien, la puissance du programmeur est bonne, il devrait donc y avoir un moyen de personnaliser le comportement. Comme la surcharge d'opérateurs (__add__, __div__, __ge__, ...), accès aux attributs (__getattribute__, __getattr__ (ces deux sont différents), __delattr__, ...) etc. Dans de nombreux cas, comme les opérateurs, la syntaxe habituelle mappe 1: 1 à la méthode respective. Dans d'autres cas, il existe une procédure spéciale qui, à un moment donné, implique l'appel de la méthode respective - par exemple, __getattr__ n'est appelé que si l'objet n'a pas l'attribut demandé et __getattribute__ n'est pas implémenté ou déclenché AttributeError. Et certains d'entre eux sont des sujets vraiment avancés qui vous plongent dans les entrailles du système d'objets et sont rarement nécessaires. Donc pas besoin de tous les apprendre, il suffit de consulter la référence lorsque vous avez besoin/voulez savoir. En parlant de référence, c'est ici .

7
user395760

Voici le créateur de Python l'expliquant :

... plutôt que de concevoir une nouvelle syntaxe pour des types spéciaux de méthodes de classe (comme les initialiseurs et les destructeurs), j'ai décidé que ces fonctionnalités pourraient être gérées en demandant simplement à l'utilisateur d'implémenter des méthodes avec des noms spéciaux tels que __init__, __del__, et ainsi de suite. Cette convention de dénomination est tirée de C où les identifiants commençant par des traits de soulignement sont réservés par le compilateur et ont souvent une signification particulière (par exemple, des macros telles que __FILE__ dans le préprocesseur C).

...

J'ai également utilisé cette technique pour permettre aux classes d'utilisateurs de redéfinir le comportement des opérateurs Python. Comme indiqué précédemment, Python est implémenté en C et utilise des tables de pointeurs de fonction pour implémenter diverses capacités d'objets intégrés (par exemple, "obtenir l'attribut", "ajouter" et "appeler"). Pour permettre à ces capacités d'être définies dans des classes définies par l'utilisateur, j'ai mappé les différents pointeurs de fonction vers des noms de méthodes spéciaux tels que __getattr__, __add__, et __call__. Il existe une correspondance directe entre ces noms et les tables de pointeurs de fonctions à définir lors de l'implémentation de nouveaux objets Python en C.

29
Steven Rumbalski

Lorsque vous démarrez une méthode avec deux traits de soulignement (et pas de traits de soulignement à la fin), les règles mangling de nom de Python sont appliquées. C'est un moyen de simuler vaguement le mot-clé private à partir d'autres langages OO tels que C++ et Java. (Même dans ce cas, la méthode n'est toujours techniquement pas privée de la manière que = Java et C++ sont privées, mais il est "plus difficile d'y accéder" depuis l'extérieur de l'instance.)

Les méthodes avec deux traits de soulignement au début et deux à la fin sont considérées comme des méthodes "intégrées", c'est-à-dire qu'elles sont utilisées par l'interpréteur et sont généralement des implémentations concrètes d'opérateurs surchargés ou d'autres fonctionnalités intégrées.

16
mipadi

Ils sont utilisés pour spécifier que l'interpréteur Python doit les utiliser dans des situations spécifiques.

Par exemple, le __add__ La fonction + opérateur pour travailler pour les classes personnalisées. Sinon, vous obtiendrez une sorte d'erreur non définie lors de la tentative d'ajout.

4
Paul Nathan

D'un point de vue historique, les traits de soulignement de tête ont souvent été utilisés comme méthode pour indiquer au programmeur que les noms doivent être considérés comme internes au package/module/bibliothèque qui les définit. Dans les langages qui ne fournissent pas une bonne prise en charge des espaces de noms privés, l'utilisation de traits de soulignement est une convention pour émuler cela. En Python, lorsque vous définissez une méthode nommée "__foo__", le programmeur de maintenance sait par son nom qu'il se passe quelque chose de spécial qui ne se produit pas avec une méthode nommée "foo". Si Python avait choisi d'utiliser 'add' comme méthode interne pour surcharger '+', alors vous ne pourriez jamais avoir une classe avec une méthode 'add' sans causer beaucoup de confusion. Les traits de soulignement servent de un signal que de la magie se produira.

3
William Pursell

Un certain nombre d'autres questions sont maintenant marquées comme des doublons de cette question, et au moins deux d'entre elles demandent ce que soit le __spam__ méthodes sont appelées, ou comment la convention est appelée, et aucune des réponses existantes ne couvre cela, donc:

Il n'y a en fait aucun nom officiel pour l'un ou l'autre.

De nombreux développeurs les appellent officieusement "méthodes dunder", pour "Double UNDERscore".

Certaines personnes utilisent le terme "méthodes magiques", mais c'est quelque peu ambigu entre la signification des méthodes dunder, des méthodes spéciales (voir ci-dessous), ou quelque chose quelque part entre les deux.


Il y a un terme officiel "attributs spéciaux", qui recoupe étroitement mais pas complètement les méthodes dunder. Le chapitre Modèle de données de la référence n'explique jamais tout à fait ce qu'est un attribut spécial, mais l'idée de base est qu'il s'agit d'au moins l'un des éléments suivants:

  • Un attribut fourni par l'interpréteur lui-même ou son code intégré, comme __name__ sur une fonction.
  • Un attribut qui fait partie d'un protocole implémenté par l'interpréteur lui-même, comme __add__ pour le + opérateur, ou __getitem__ pour l'indexation et le découpage.
  • Un attribut que l'interpréteur est autorisé à rechercher spécialement, en ignorant l'instance et en allant directement à la classe, comme __add__ encore.

La plupart des attributs spéciaux sont des méthodes, mais pas tous (par exemple, __name__ n'est pas). Et la plupart utilisent la convention "dunder", mais pas toutes (par exemple, la méthode next sur les itérateurs dans Python 2.x).

Et pendant ce temps, la plupart des méthodes dunder sont des attributs spéciaux, mais pas tous - en particulier, il n'est pas rare que stdlib ou des bibliothèques externes veuillent définir leurs propres protocoles fonctionnant de la même manière, comme le pickle protocole.

1
abarnert

[Spéculation] Python a été influencé par ALGOL68 , Guido a peut-être utilisé ALGOL68 au niversité d'Amsterdam où ALGOL68 a un " régime stropping " similaire appelé "Quote stropping". Dans ALGOL68, les opérateurs, types et mots-clés peut apparaissent dans une police différente (généralement ** gras **, ou __ souligné __), dans les fichiers de code source, cette police est réalisée avec des guillemets, par exemple 'abs' (citation similaire à la citation entre ' wikitext ')

ALGOL68 ⇒ Python (Opérateurs mappés aux fonctions membres)

  • 'et' ⇒ __and__
  • 'ou' ⇒ __or__
  • 'pas' ⇒ pas
  • 'entier' ⇒ __trunc__
  • 'shl' ⇒ __lshift__
  • 'shr' ⇒ __rshift__
  • 'upb' ⇒ __sizeof__
  • 'long' ⇒ __long__
  • 'int' ⇒ __int__
  • 'réel' ⇒ __float__
  • 'format' ⇒ __format__
  • 'repr' ⇒ __repr__
  • 'abs' ⇒ __abs__
  • 'moins' ⇒ __neg__
  • 'moins' ⇒ __sub__
  • 'plus' ⇒ __add__
  • 'fois' ⇒ __mul__
  • 'mod' ⇒ __mod__
  • 'div' ⇒ __truediv__
  • 'au-dessus' ⇒ __div__
  • 'up' ⇒ __pow__
  • 'im' ⇒ imag
  • 're' ⇒ réel
  • 'conj' ⇒ conjugué

Dans ALGOL68, on les appelait noms gras , par exemple abs , mais "under-under-abs" __abs__ en python.

Mes 2 cents: ¢ Donc parfois - comme un fantôme - quand vous coupez et collez python classes dans un wiki, vous réincarnez comme par magie ALGOL68 bold mots-clés. ¢

0
NevilleDNZ