Des exemples concrets de la maxime «une seule façon de faire» de Python [fermé]

34

J'apprends le python et je suis intrigué par le point suivant dans PEP 20 Le zen de Python :

Il devrait y avoir une - et de préférence une seule - manière évidente de le faire. Bien que cela ne soit pas évident au premier abord, sauf si vous êtes néerlandais.

Quelqu'un pourrait-il offrir des exemples concrets de cette maxime? Je suis particulièrement intéressé par le contraste avec d'autres langues telles que le rubis. Une partie de la philosophie de conception de Ruby (issue de Perl, je pense?) Est que de multiples façons de le faire est une bonne chose. Quelqu'un peut-il offrir des exemples montrant les avantages et les inconvénients de chaque approche? Notez que je ne cherche pas une réponse meilleure (probablement trop subjective que jamais), mais plutôt une comparaison impartiale des deux styles.

Charles Roper
la source

Réponses:

47

Comparé à des langages tels que Perl, Python possède un nombre limité de constructions de contrôle:

  • seulement ifet non unless,
  • seulement forque itère sur des séquences et pas foreachou C-style for,
  • seulement whilecela vérifie une condition à chaque boucle et non do-while,
  • seulement if-elifet non switch,
  • il n'y a qu'une seule construction de commentaire, le #, et pour chaque ligne, vous pouvez dire si elle est commentée ou non, sans regarder les lignes précédentes.

En outre, il existe presque une façon d'indenter votre source; la plupart des cas d'indentation créative sont syntaxiquement exclus.

Cela facilite l'analyse d'une source Python pour les humains.

Il existe des tentatives pour être minimal mais complet dans les types intégrés et la bibliothèque standard.

  • pour la liste mutable, vous utilisez le seul type intégré list; c'est O (1) pour la plupart des opérations, et vous n'avez jamais à choisir la bonne implémentation,
  • pour les listes immuables, vous devez également utiliser le tupletype,
  • pour les cartes, vous utilisez le seul dictoutil intégré qui est sacrément efficace dans la plupart des cas, inutile de vous demander quelle implémentation utiliser.

Python 3 étend cela aux entiers: quelle que soit la taille de votre entier, vous utilisez le même type et ne vous souciez jamais de la contrainte.

Python essaie d'éviter le sucre syntaxique. Mais parfois, il ajoute du sucre syntaxique simplement pour mettre en évidence le moyen évident. Vous pouvez écrire if foo is not Noneau lieu de if not (foo is None)parce que 'is not' est une casse spéciale. Lit toujours foo is not Nonefacilement, ne peut pas être mal interprété, et vous n'avez pas à penser, vous écrivez simplement la chose évidente.

Bien sûr, la plupart des choses plus complexes en Python peuvent être effectuées de plusieurs manières. Vous pouvez ajouter des méthodes aux classes par déclaration ou par simple affectation d’emplacement, vous pouvez transmettre des arguments à des fonctions de différentes manières, etc. Tout simplement parce que les éléments internes du langage sont principalement exposés.

La clé est qu'il y a toujours un moyen qui se veut être le meilleur, le "cover-all". Si d'autres moyens existent, ils n'ont pas été ajoutés en tant qu'alternatives égales (comme ifet unless), mais ont simplement exposé le fonctionnement interne. Lentement mais sûrement, de telles alternatives sont obsolètes (pas éliminées!) En améliorant le meilleur mécanisme connu.

Les décorateurs encapsulent les appels de fonction AOP. Avant la version 2.6, vous deviez utiliser __metaclass__membre magique pour déclarer la métaclasse d'une classe. Maintenant, vous pouvez aussi utiliser la même syntaxe de décorateur. Avant la version 3.0, vous disposiez de deux types de chaînes, orientées octets et Unicode, que vous pouviez mélanger par inadvertance. Vous avez maintenant le seul Unicode stret le seul transparent binaire bytes, que vous ne pouvez pas mélanger par erreur.

9000
la source
3
Juste comme une note, n'oubliez pas les """commentaires (docstrings). Celles-ci s'étendent sur plusieurs lignes.
asthasr
8
Les littéraux à trois guillemets ne sont que des chaînes, identiques à des guillemets simples, mais peuvent s'étendre sur plusieurs lignes sans échapper des fins de ligne. Un littéral de chaîne juste après la déclaration est considéré comme une chaîne de documentation. Ce n'est pas un commentaire, il est généralement accessible en tant __doc__qu'attribut. Mais les chaînes de caractères constituent un domaine dans lequel Python fournit définitivement de nombreuses «méthodes correctes»: utilisez des guillemets simples, doubles ou triples, joignez implicitement les littéraux adjacents, utilisez-les rpour les littéraux bruts, etc.
9000
1
Je pense que le commentaire de @ syrion concernait le "vous pouvez toujours décider si une ligne est commentée ou non en la regardant", ce qui n'est pas vrai à cause des chaînes "" ".
blubb
2
"Cela facilite l'analyse d'une source Python pour les humains." <- c'est subjectif
Jiggy
Comment la déclaration de métaclasse a-t-elle changé en 2.7? Impossible de trouver le motif de décorateur dans la documentation 2.7 pour les métaclasses.
Nick T
10

Voici deux autres exemples:
len()est une fonction au lieu d’une méthode présente dans chaque séquence; si vous comparez avec Java que vous avez .length, .size(), .getSize()et d' autres méthodes pour trouver le nombre d'éléments dans une séquence.

Un autre exemple est le fait qu'il .join()s'agit d'une stringméthode et non d'une méthode présente dans chaque séquence. Vous n'avez pas besoin de savoir si le paramètre join est une liste, un ensemble, une compréhension ou quoi que ce soit d'autre, cela fonctionnera.

Vito De Tullio
la source
8

En C, il y a plusieurs façons d'augmenter la valeur d'une variable d'une unité:

i++     // Post-increment, returns the number before the increment
++i     // Pre-increment, returns the number after the increment
i += 1 

Chaque finit par augmenter la valeur ipar 1, mais chacun d' eux est légèrement différente.

En Python, il n'y a vraiment qu'un seul moyen; il suffit d'en ajouter un.

i += 1

Et bien qu'il existe plus d'une façon syntaxiquement valide de faire cela (par exemple i = i + 1), vous faites la même chose avec les mêmes effets secondaires.


la source
1
Je ne suis pas un expert, mais cet exemple semble violer précisément l'idée du "une seule façon de le faire". Nous avons deux façons de le faire, mais quelle est la plus évidente? À mes yeux, le premier exemple est plus évident tandis que le second est un peu plus concis, mais non moins lisible ou évident pour tout programmeur qui a progressé au-delà des bases. Merci pour votre réponse - c'est un bon sujet de réflexion.
Charles Roper
@Peter (et @Charles): En fait, i = i + 1c'est une cession, pas un incrément. En python, un incrément est i += 1. Dans les langues de style C vous pouvez écrire i++, ++iet i += 1.
Josh K
2
Pas sûr de votre commentaire "beaucoup de confusion", vos trois exemples C (vous avez manqué i += 1, BTW) produisent exactement le même résultat. La seule fois où je vois des gens devenir confus, c'est quand ils pré-incrémentent ou post-incrémentent une variable dans le cadre d'une expression plus grande, ce qui est généralement corrigé rapidement en lisant la section appropriée de la référence du langage. Personnellement, j'aurais compris le fait que vous pouvez faire référence au cinquième caractère d'une chaîne à la fois str[4]ou *(str+4), mais peut-être que c'était trop facile ...
TMN
2
@TMN: certains cas, comme par exemple, max(i++, ++i)ne peuvent pas être rapidement résolus. C a beaucoup de cas de comportement "non définis" et "dépendants de la mise en oeuvre", le tout pour une bonne raison - mais chacun peut créer un piège.
9000
@TMN: Sans oublier 4 [str] (valide en C, peut ne pas être valide en C ++).
Vatine
6

Une autre possibilité pourrait être la compréhension de liste. En Python, vous pouvez faire ceci:

new_list = []
    for item in list_of_items:
       if item < 10:
           new_list.append(item)

Mais la manière "évidente" (si vous êtes néerlandais ou êtes plus familier avec Python) de le faire serait d'utiliser une liste de compréhension:

new_list = [item for item in list_of_items if item < 10]

C'est plus court, la new_list est créée en une étape, elle court plus vite, je crois, et elle est élégante. En revanche, on pourrait dire que cela semble moins explicite, mais je pense qu'une fois que vous vous y êtes habitué, c'est tout aussi explicite.

Chélonien
la source
Pour l'indentation et le code: ajoutez 4 espaces, puis respectez l'indentation.
Inca