67 votes

Est-ce que "import module" est un meilleur style de codage que "from module import function" ?

Soit from module import function être appelé le style de codage FMIF.

Soit import module être appelé le style de codage IM.

Soit from package import module être appelé le style de codage FPIM.

Pourquoi IM+FPIM est-il considéré comme un meilleur style de codage que FMIF ? (Voir ce poste pour l'inspiration de cette question).

Voici quelques critères qui me conduisent à préférer le FMIF à l'IM :

  1. La brièveté du code : Cela me permet d'utiliser des noms de fonctions plus courts et donc de respecter la convention des 80 colonnes par ligne.
  2. Lisibilité : chisquare(...) semble plus lisible que scipy.stats.stats.chisquare(...) . Bien qu'il s'agisse d'un critère subjectif, je pense que la plupart des gens seraient d'accord.
  3. Facilité de réorientation : Si j'utilise FMIF et que, pour une raison quelconque, je souhaite par la suite rediriger python vers la définition de function de alt_module au lieu de module Je dois changer une seule ligne : from alt_module import function . Si je devais utiliser la MI, je devrais modifier de nombreuses lignes de code.

Je sais que le MIFP annule en partie les deux premiers points, mais qu'en est-il du troisième ?

Je suis intéressé par toutes les raisons pour lesquelles IM+FPIM peut être meilleur que FMIF, mais en particulier, j'aimerais avoir des précisions sur les points suivants mentionné ici :

Les avantages pour la GI :

  1. la facilité d'utilisation de la simulation et de l'injection dans les tests. (Je ne suis pas très familier avec le mocking, même si j'ai récemment appris ce que ce terme signifie. Pouvez-vous montrer un code qui démontre en quoi IM est meilleur que FMIF ici) ?
  2. la possibilité pour un module d'évoluer de manière flexible en redéfinissant certaines entrées. (Je dois avoir mal compris quelque chose, car cela semble être un avantage de FMIF par rapport à IM. Voir ma troisième raison en faveur de FMIF ci-dessus).
  3. un comportement prévisible et contrôlable sur la sérialisation et la récupération de vos données. (Je ne comprends vraiment pas comment le choix de IM ou FMIF affecte cette question. Veuillez élaborer).
  4. Je comprends que le FMIF "pollue mon espace de noms", mais au-delà de cette expression à consonance négative, je ne vois pas en quoi cela nuit au code de manière concrète.

PS. En écrivant cette question, j'ai reçu un avertissement indiquant que la question semble subjective et qu'elle risque d'être fermée. Ne la fermez pas, s'il vous plaît. Je ne cherche pas à obtenir une opinion subjective, mais plutôt des situations de codage concrètes dans lesquelles IM+FPIM est manifestement meilleur que FMIF.

Merci beaucoup.

45voto

Alex Martelli Points 330805

Les points négatifs que vous énumérez pour le MIGI/PFIM peuvent souvent être améliorés par l'utilisation appropriée d'un système de gestion de l'information. as clause. from some.package import mymodulewithalongname as mymod peut utilement raccourcir votre code et améliorer sa lisibilité, et si vous renommez mymodulewithalongname a somethingcompletelydifferent demain, le as peut être utilisée comme une seule déclaration à modifier.

Considérez votre point 3 pro-FMIF (appelé R pour redirection) par rapport à votre point 2 pro-FPIM (appelé F pour flexibilité) : R revient à faciliter la perte d'intégrité des limites des modules, alors que F la renforce. Les fonctions, classes et variables multiples d'un module sont souvent destinées à fonctionner ensemble : elles ne devraient pas être indépendamment commutées vers des significations différentes. Par exemple, considérons le module random et ses fonctions seed y uniform si vous changez l'importation d'un seul d'entre eux vers un module différent, vous romprez la connexion normale entre les appels à seed et les résultats des appels à uniform . Lorsqu'un module est bien conçu, avec de la cohésion et de l'intégrité, le fait que R facilite l'éclatement des limites du module est en fait négatif - il rend plus facile de faire quelque chose qu'il vaut mieux ne pas faire. no faire.

Vice versa, F est ce qui permet coordonné commutation de fonctions, de classes et de variables couplées (donc, en général, d'entités qui appartenir à ensemble, par modularité). Par exemple, pour que les tests soient reproductibles (point 1 du modèle FPIM), il faut simuler les deux éléments suivants seed y random dans le random et si votre code suit le FPIM, tout est prêt, coordination garantie ; mais si votre code a importé les fonctions directement, vous devez rechercher chacun de ces modules et répéter le mocking encore et encore et encore. Pour que les tests soient parfaitement répétables, il faut également coordonner les fonctions de date et d'heure. from datetime import datetime dans certains modules, vous devez tous les trouver et vous moquer d'eux (ainsi que de ceux qui font des from time import time etc.) afin de garantir que toutes les heures reçues lorsque les différentes parties du système demandent "quelle heure est-il maintenant ?" sont parfaitement cohérentes (si vous utilisez le FPIM, il vous suffit de simuler les deux modules pertinents).

J'aime le FPIM, parce qu'il n'y a pas vraiment de valeur ajoutée en utilisant un multiplier plutôt qu'un nom mono-qualifié (alors que la différence entre les noms nus et les noms qualifiés est de 10 %). énorme -- vous obtenez donc beaucoup plus de contrôle avec un nom qualifié, qu'il soit unique ou multiple, que vous ne pourrez jamais le faire avec un nom nu !)

Ah bon, je ne peux pas consacrer toute la journée de travail à répondre à chacun de vos points - votre question devrait probablement être une demi-douzaine de questions;-). J'espère que cela répond au moins à la question "pourquoi F est-il meilleur que R" et à certains problèmes de simulation et de test. préserver et renforcer une modularité bien conçue (via F) plutôt que de l'affaiblir (via R).

17voto

Daniel Roseman Points 199743

Le texte classique à ce sujet, comme souvent, est celui de Fredrik Lundh, l'effbot. Son conseil : toujours utiliser l'importation - sauf quand tu ne devrais pas.

En d'autres termes, soyez raisonnable. Personnellement, je trouve que tout ce qui a plusieurs modules de profondeur a tendance à être importé par le biais de from x.y.z import a - le principal exemple étant les modèles Django. Mais, comme tout le reste, c'est une question de style, et vous devriez en avoir un cohérent, surtout avec des modules comme datetime où le module et la classe qu'il contient ont le même nom. Avez-vous besoin d'écrire datetime.datetime.now() ou simplement datetime.now() ? (Dans mon code, toujours le premier).

Les points 1 et 2 de votre liste de questions semblent être le même problème. La nature dynamique de Python signifie qu'il est assez simple de remplacer un élément dans l'espace de noms d'un module, quelle que soit la méthode que vous utilisez. La difficulté vient lorsqu'une fonction d'un module fait référence à une autre, qui est celle que vous voulez simuler. Dans ce cas, l'importation du module plutôt que des fonctions vous permet de faire module.function_to_replace = myreplacementfunc et tout fonctionne de manière transparente - mais cela est aussi facile à faire via le MIPF que via la messagerie instantanée.

Je ne comprends pas non plus en quoi le point 3 a un rapport avec quoi que ce soit. Je pense que votre point 4, en revanche, est basé sur un petit malentendu. Aucune des méthodes que vous citez ne va "polluer votre espace de noms". Ce que fait faire qui est from module import * Vous n'avez aucune idée de ce que vous importez et des fonctions peuvent apparaître dans votre code sans que le lecteur sache d'où elles viennent. C'est horrible, et il faut l'éviter à tout prix.

7voto

MestreLion Points 1789

Les réponses sont excellentes (je les ai toutes approuvées), et voici ce que je pense de cette question :

D'abord, en abordant chacune de vos balles :

(Prétendument) Les avantages du FMIF :

  • La brièveté du code : des noms de fonctions plus courts aident à respecter les 80 colonnes par ligne.

Peut-être, mais les noms des modules sont généralement suffisamment courts pour que cela ne soit pas pertinent. Bien sûr, il y a datetime mais aussi os , re , sys etc. Et Python a des sauts de ligne libres à l'intérieur { [ ( . Et pour les modules imbriqués, il y a toujours as dans le MGI et le MIPF

  • Lisibilité : chisquare(...) semble plus lisible que scipy.stats.stats.chisquare(...).

Pas du tout d'accord. Lorsque je lis du code étranger (ou mon propre code après quelques mois), il est difficile de savoir d'où vient chaque fonction. Les noms qualifiés m'évitent de faire des allers-retours entre la ligne 2345 et l'en-tête des déclarations de modules. Et cela vous donne aussi contexte : " chisquare ? Qu'est-ce que c'est ? Oh, ça vient de scypy ? Ok, des trucs liés aux maths alors" . Et, encore une fois, vous pouvez toujours abréger scipy.stats.stats as scypyst . scypyst.chisquare(...) est suffisamment court et présente tous les avantages d'un nom qualifié.

import os.path as osp est un autre bon exemple, étant donné qu'il est très courant de chaîner 3 ou plus de ses fonctions en un seul appel : join(expanduser(),basename(splitext())) etc.

  • Facilité de redirection : redéfinition en une ligne d'une fonction de altmodule au lieu de module.

Combien de fois voulez-vous redéfinir une seule fonction mais pas le module entier ? Les limites du module et la coordination des fonctions doivent être préservées, et Alex a déjà expliqué cela en profondeur. Pour la plupart (tous ?) des scénarios du monde réel, si alt_module.x est un remplacement viable de module.x alors probablement alt_module est en soi une solution de remplacement pour module Ainsi, IM et FPIM sont tous deux des lignes uniques, tout comme FMIF, à condition que vous utilisiez la fonction as .

  • Je réalise que le MIFP annule en partie les deux premiers problèmes...

En fait, as est celui qui atténue les deux premiers problèmes (et le troisième), pas le MIPF. Vous pouvez également utiliser le MIF pour cela : import some.long.package.path.x as x pour obtenir le même résultat que le MIPF.


Ainsi, aucun des éléments ci-dessus n'est réellement un avantage du FMIF. Et les raisons pour lesquelles je préfère IM/FPIM sont :

Pour des raisons de simplicité et de cohérence, lorsque j'importe quelque chose, que ce soit du MI ou du MIPF, j'importe toujours un fichier module et non un objet d'un module. N'oubliez pas que le FMIF peut être (ab-)utilisé pour importer des fonctions, des classes, des variables ou même d'autres modules ! Pensez à la pagaille de from somemodule import sys, somevar, os, SomeClass, datetime, someFunc .

De plus, si vous souhaitez obtenir plus d'un objet d'un module, FMIF polluera davantage votre espace de noms que IM ou FPIM, qui utiliseront un seul nom, quel que soit le nombre d'objets que vous souhaitez utiliser. Et ces objets auront un qualifié nom, ce qui est un avantage et non un inconvénient : comme je l'ai dit dans le numéro 2, IMHO un it améliore la lisibilité.

tout se résume à la cohérence, la simplicité, l'organisation. "Importez des modules, pas des objets" est un bon modèle mental facile à suivre.

6voto

steveha Points 24808

Comme Alex Martelli, j'aime bien utiliser as lors de l'importation d'une fonction.

Une chose que j'ai faite est d'utiliser un préfixe sur toutes les fonctions qui ont été importées du même module :

from random import seed as r_seed
from random import random as r_random

r_seed est plus court à taper que random.seed mais préserve quelque peu les limites du module. Quelqu'un qui regarde par hasard votre code peut voir r_seed() y r_random() et avoir une chance de comprendre qu'ils sont liés.

Bien sûr, vous pouvez toujours vous contenter de faire :

import random as r

et ensuite utiliser r.random() y r.seed() ce qui peut être le compromis idéal pour ce cas. Je n'utilise l'astuce du préfixe que lorsque j'importe une ou deux fonctions d'un module. Lorsque je veux utiliser de nombreuses fonctions du même module, j'importe le module, éventuellement avec un préfixe as pour raccourcir le nom.

1voto

Aaron Hall Points 7381

Je suis le plus d'accord avec MestreLion ici (et donc un upvote).

Mon point de vue : Je révise fréquemment du code qui ne m'est pas familier, et ne pas savoir de quel module provient une fonction simplement en regardant la fonction est assez frustrant.

Le code est écrit une fois et lu de nombreuses fois. La lisibilité et la maintenabilité l'emportent donc sur la facilité de frappe.

Dans le même ordre d'idées, le code est généralement no être écrit pour le bénéfice du codeur, mais pour le bénéfice d'une autre entité.

Votre code doit être lisible pour quelqu'un qui connaît mieux que vous le langage python, mais qui n'est pas familier avec le code.

Les importations de chemins complets peuvent également aider les IDE à vous orienter vers la source correcte de la fonction ou de l'objet que vous recherchez.

Pour toutes ces raisons et celles que MestreLion a notées, je conclus que la meilleure pratique consiste à importer et à utiliser le chemin complet.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X